JavaScript 是单线程运行的,因此异步操作特别重要。 为了协调异步任务,Node提供了四个定时器,让任务可以在指定的时间运行。
● setTimeout()
● setInterval()
● setImmediate()
● process.nextTick()
复制代码
前两个是js语言的标准,后两个是 Node 独有的。
有如下一个js文件
// test.js
setTimeout(() => console.log(1));
setImmediate(() => console.log(2));
process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));
(() => console.log(5))();
复制代码
执行该文件:
$ node test.js
5
3
4
1
2
复制代码
异步任务可以分成两种。
● 追加在本轮循环的异步任务
● 追加在次轮循环的异步任务
process.nextTick这个名字有点误导,它是在本轮循环执行的,而且是所有异步任务里面最快执行的。 Promise对象的回调函数,会进入异步任务里面的”微任务”(microtask)队列。 微任务队列追加在process.nextTick队列的后面,也属于本轮循环。
注意,只有前一个队列全部清空以后,才会执行下一个队列
Node 规定,process.nextTick和Promise的回调函数,追加在本轮循环,即同步任务一旦执行完成,就开始执行它们。而setTimeout、setInterval、setImmediate的回调函数,追加在次轮循环
process.nextTick(() => console.log(1));
Promise.resolve().then(() => console.log(2));
process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));
// 1 // 3 // 2 // 4
复制代码
全部process.nextTick的回调函数,执行都会早于Promise的。
只有一个主线程,事件循环是在主线程上完成的。
Node 开始执行脚本时,会先进行事件循环的初始化,但是这时事件循环还没有开始,会先完成下面的事情。
● 同步任务
● 发出异步请求
● 规划定时器生效的时间
● 执行process.nextTick()等
然后就开始事件循环阶段,事件循环会无限次地执行,一轮又一轮。只有异步任务的回调函数队列清空了,才会停止执行。