一个经典的 Node Web 应用程序

  • nodejs 是一个 JavaScript 运行平台,显著特征是它的异步和事件驱动机制以及小巧精悍的标准库。
  • nodejs 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。

非阻塞 I/O

  • 含义:你的程序可以在做其他事情时发起一个请求来获取网络资源,然后当网络操作完成时,将会运行一个回调函数来处理这个操作的结果。

非阻塞网络操作

  • Node 中的网络访问是非阻塞的,它用了一个名为 libuv 的库来访问操作系统的非阻塞网络调用。
  • 例如,用 JavaScript 操作数据库的 JavaScript,只要写一些 db.insert(query, err => {}) 这样的代码,Node 就会帮你完成那些经过高度优化的非阻塞网络操作。
  • 较耗时的异步 I/O 操作会被放到异步模块中在后台执行,不会影响其他代码在 JS 主线程(调用栈)的执行。
  • JS 主线程(调用栈)会想方设法地一次次清空调用栈,由于速度极快,所以有种并发的错觉。
  • 在进行速度较慢的处理时让 Node 能做其他事情,是使用带非阻塞 I/O 的异步 API 真正的好处。

事件循环监听异步模块的处理结果,一旦处理完成,就将其对应回调函数放入到对应的事件循环队列中等待被派发到调用栈中执行。

调用栈执行事件循环中回调的时机为:调用栈中没有正在执行的 task() 时,JS 主线程(调用栈)会把事件循环队列中的回调函数依次取出,放入到调用栈中执行,直到清空事件循环队列,即调用栈再次执行下一个 JS 文件,事件循环完成一次,依次往复。

即便你只有一个单线程、单进程的 Node Web 应用,它也可以同时处理上千个网站访客发起的连接。要想知道 Node 是如何做到的,得先研究一下事件轮询(事件循环队列)。

事件轮询(事件循环

  • 事件循环队列分为 Timer、Poll、Check 队列
  • 事件轮询发生在 Timer 队列中,Poll 队列中,Check 队列中。
  • 轮询机制简述:进入事件循环后,先执行 Timer 队列中的任务,然后执行 Poll 队列中的任务,若 Check 队列中没有回调函数时则停留在 Poll 队列中,若有,则顺序执行-循环。
  • 轮询机制细节:事件循环队列为空时,会停留在 Poll 队列中等待,以避免无意义的循环,在 Poll 队列中等待这也导致了从异步模块结束的 I/O 回调进入 Poll 队列时会被优先执行(一般 I/O 回调是响应用户的行为),在 Poll 队列挂起等待过程中,若其他队列有回调时,也会去处理,然后按循环顺序执行,再回到 Poll 队列挂起等待。因此,从设计本意上看, Node 希望优先处理 I/O 事件回调来响应用户,这也就为 Node Web 应用同时处理上千个网站访客发起的连接创造了条件。
  • 尽管 Node 是单线程的,但你仍然可以用它提供的工具写出可伸缩的高效代码。

V8 —— 让 JS 充分释放潜能

  • Node 的动力源自 V8 JavaScript 引擎,V8 引擎是 Google 开源的,它使得 JS 在浏览器之外也可以运行。
  • V8 的一个特性是它会讲 JavaScript 直接编译为机器码,另外它还有一些代码优化特性,所以 Node 才能这么快。
  • 组成 Node 的所有软件组件:

  • 特性组:Node 中能用的 JavaScript 特性(ES6+语法)都可以追溯到 V8 对该特性的支持。这一支持是通过特性组来管理:

    1. shipping:默认开启 —— 成熟可靠的 JavaScript 特性
    2. staged:node index.js --harmony staged —— 所有接近完成的特性
    3. in progress:特性稳定性较差,需要具体的特性参数来开启

Node 自带的工具

npm

  • 用途:用命令行工具 npm 安装 npm 注册中心 里的包
  • 安装参数:
  1. --save:
  2. --development
  3. --save-dev
  4. --global

核心模块

  • Node 的核心模块是编写服务器端 JavaScript 所需的工具。
  • Node 以最少的代码给它加上了文件和 TCP/IP 网络功能,使其成为了一个可用的服务器端编程语言。
  • ==Node 扩展了 JavaScript 的能力(文件读写、异步 I/O、网络...),V8 引擎负责解释和执行 JavaScript==
// 使用核心模块和流进行压缩
const  fs = require('fs')
const  zlib = require('zlib')
const  gzip = zlib.createGzip()
const  outStream = fs.createWriteStream('output.js.gz')

fs.createReadStream('./node-stream.js').pipe(gzip).pipe(outStream)

调试器(第九章详述)

三种主流的 Node 程序

  • Web 应用程序、命令行工具和后台程序、桌面程序。

    1. Web 应用程序:单页应用的简单程序、REST 微服务以及全栈的 Web 应用
    2. 命令行工具:npm、Gulp 和 Webpack
    3. 后台程序:PM2 进程管理器
    4. 桌面程序:Electron 框架写的软件