Node.js 学习(持续更新中...)

597 阅读2分钟

为什么说 Node.js 是单线程的?

一般人理解 Node 是单线程的,所以 Node 启动后线程数应该为 1,我们做实验看一下。

setInterval(() => {
  console.log(new Date().getTime())
}, 3000)

可以看到 Node 进程占用了 7 个线程(注意:不同版本 node 占用的线程数可能不一致)。为什么会有 7 个线程呢?

我们都知道,Node 中最核心的是 V8 引擎,在 Node 启动后,会创建 V8 实例,这个实例是多线程的。

  • 主线程:编译、执行代码。
  • 编译/优化线程:在主线程执行的时候,可以优化代码。
  • 分析器线程:记录分析代码运行时间,为 Crankshaft 优化代码执行提供依据。
  • 垃圾回收的几个线程。

所以大家常说的 Node 是单线程的指的是 JavaScript 的执行是单线程的,但 Javascript 的宿主环境,无论是 Node 还是浏览器都是多线程的。

为什么 Node.js 不适合 CPU 密集型操作,适合 I/O 密集型操作?

Node 适合 I/O 密集型操作,是因为 V8 通过 Node api (c++ 接口) 将 I/O 等异步任务交给了 libuv 线程池里的线程来完成,不会阻塞主线程执行。而你的 JS 运算代码(CPU 密集型操作),是无法交给 libuv 里的线程来处理的,只能运行在主线程,运算量过大就会阻塞主线程后续代码,当然 NodeJs 也可以通过 cluster / child_process / work_threads 等方式,启用多进程/多线程来处理 CPU 密集型的任务,但相比其它成熟的方案并没有优势。

exports & module.exports 的区别?

exports = module.exports = {},exports 只是 module.exports 的引用,require 引入的是 module.exports 对应的对象。为了避免糊涂,尽量都用 module.exports 导出。

exports.name = 'Alan';
exports.test = function () {
  console.log('hi')
};
console.log(module) // module: { exports: { name: 'Alan', test: [Function] } }

// exports 初始值是 module.exports 的引用,可以给它赋值另一个对象,但不会修改导出的对象
exports = {
  name: 'Bob',
  add: function (a, b) {
    return a + b;
  }
}
console.log(exports) // { name: 'Bob', add: [Function] }
console.log(module) // module: { exports: { name: 'Alan', test: [Function] } }

cluster / child_process / work_threads 的区别?

Node 中提供了 cluster 模块,cluster 实现了对 child_process 的封装,通过 fork 方法创建子进程的方式实现了多进程模型,无论 child_process 还是 cluster,都不是多线程模型,而是多进程模型。

Node 10.5.0 的发布,官方才给出了一个实验性质的模块 worker_threads 给 Node 提供真正的多线程能力。

链接

以下链接是我最近学 Node.js 觉得还不错的:

Node入门

真-Node多线程

深入浅出Node.js 中的进程与线程

Node.js 软肋之 CPU 密集型任务