# 事件循环

文档

# event loop

  1. timers阶段

此阶段包括setTimeout()和setInterval()

  1. IO callbacks

大部分的回调事件,普通的callback

  1. poll阶段

网络连接,数据获取,读取文件等操作

  1. check阶段

setImmediate()在这里调用回调

  1. close阶段

一些关闭回调,例如socket.on('close', ...)

# question

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}
async function async2() {
  console.log("async2");
}
console.log("script start");
setTimeout(function() {
  console.log("setTimeout0");
});
setTimeout(function() {
  console.log("setTimeout3");
}, 3);
setImmediate(function() {
  console.log("setImmediate");
});
process.nextTick(() => console.log("nextTick"));
async1();
new Promise((resolve) => {
  console.log("promise1");
  resolve();
  console.log("promise2");
}).then(() => {
  console.log("promise3");
});
console.log("script end");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# answer

script start
async1 start
async2
promise1
promise2
script end
nextTick
async1 end
promise 
setTimeout 0
setImmediate
setTimeout 3
1
2
3
4
5
6
7
8
9
10
11
12

后三项也有可能是如下:

setTimeout 0
setTimeout 3
setImmediate
或者
setImmediate
setTimeout 0
setTimeout 3
1
2
3
4
5
6
7

解释:

这是因为 setTimeout 的第二个参数默认为0。但是实际上,Node 做不到0毫秒,最少也需要1毫秒,根据官方文档,第二个参数的取值范围在1毫秒到2147483647毫秒之间。也就是说,setTimeout(f, 0)等同于setTimeout(f, 1)。

实际执行的时候,进入事件循环以后,有可能到了1毫秒,也可能还没到1毫秒,取决于系统当时的状况。如果没到1毫秒,那么 timers 阶段就会跳过,进入 check 阶段,先执行 setImmediate 的回调函数。

但是,下面的代码一定是先输出2,再输出1。

const fs = require('fs');
fs.readFile('test.js', () => {
  setTimeout(() => console.log(1));
  setImmediate(() => console.log(2));
});
1
2
3
4
5

上面代码会先进入 I/O callbacks 阶段,然后是 check 阶段,最后才是 timers 阶段。因此,setImmediate才会早于setTimeout执行。

# process.nextTick

  • Node执行完所有同步任务,接下来就会执行 process.nextTick 的任务队列。

  • 开发过程中如果想让异步任务尽可能快地执行,可以使用 process.nextTick 来完成

# 微任务microtask队列

微任务队列追加在 process.nextTick 队列的后面

promise回调
1

# 宏任务macrotask队列

setTimeout
setInterval
setImmediate
1
2
3
  • 事件循环中的setTimeOut与setImmediate

由于 setTimeout 在 timers 阶段执行,而 setImmediate 在 check 阶段执行。所以,setTimeout 会早于 setImmediate 完成。

setTimeout(() => console.log(1))
setImmediate(() => console.log(2))
1
2

上面结果是不确定的。

这是因为 setTimeout 的第二个参数默认为0。但是实际上,Node 做不到0毫秒,最少也需要1毫秒,根据官方文档,第二个参数的取值范围在1毫秒到2147483647毫秒之间。也就是说,setTimeout(f, 0)等同于setTimeout(f, 1)。

实际执行的时候,进入事件循环以后,有可能到了1毫秒,也可能还没到1毫秒,取决于系统当时的状况。如果没到1毫秒,那么 timers 阶段就会跳过,进入 check 阶段,先执行 setImmediate

但是,下面的代码一定是先输出2,再输出1。

const fs = require('fs');
fs.readFile('test.js', () => {
  setTimeout(() => console.log(1))
  setImmediate(() => console.log(2))
});
1
2
3
4
5

上面代码会先进入 I/O callbacks 阶段,然后是 check 阶段,最后才是 timers 阶段。因此,setImmediate才会早于setTimeout执行。

上次更新: 2020-03-05 05:45:55