Menu
CoddyTech

事件循环

本课属于 Coddy Node.js 学习旅程的“Node.js 基础”单元。第 26 课,共 33 课。

回调和 Promise 会稍后运行,弄不清它们确切的运行时间,就容易藏着错误。

Node 会先运行所有同步代码,直到结束。然后运行微任务:Promise 回调和传给 queueMicrotask 的函数。之后才运行定时器。setTimeout(fn, ms) 会在 ms 毫秒后运行一次 fn。即使是 setTimeout(fn, 0),也要等微任务完成后才会运行。

setTimeout(() => console.log('C timer'), 0);
Promise.resolve().then(() => console.log('B promise'));
console.log('A sync');
// A sync, B promise, C timer

延迟为 0 表示在微任务完成后尽快运行,而不是在它们之前运行。定时器按延迟时间的顺序触发;延迟相同时,先设置的定时器先触发。

challenge icon

挑战

简单

Node 会按固定顺序运行代码。先运行普通语句,然后运行微任务,例如 Promise 回调,最后运行计时器。利用这个顺序,让四行内容按数字顺序打印出来,同时不移动它们。

order.js 中的四行内容会从 4 到 1 打印出来。不要移动或重新排列这些行,而是把其中三行分别包装起来,让它们稍后运行。

  1. 保持 console.log('1 sync') 不变。普通代码会先运行。
  2. 用 queueMicrotask 包装 2 microtask 这一行,让它在普通代码之后立即运行。
  3. 分别用各自的 setTimeout 包装 3 timeout 这一行和 4 timeout later 这一行。setTimeout(fn, ms) 会在 ms 毫秒后运行一次函数 fn。第 4 行在第 3 行之前设置,因此需要设置更长的延迟。

然后,运行 node order.js 会打印:

1 sync
2 microtask
3 timeout
4 timeout later

试试看:运行之前,先猜猜输出顺序。然后按下“运行”,终端会显示 $ node order.js。接着,把两个计时器的延迟都设为 0,再运行一次:此时 4 timeout later 会先于 3 timeout 打印,因为延迟相同时,先设置的计时器会先运行。按下“检查”之前,记得把第 4 行的延迟改回较长的值。

亲手试试

// 不要移动这些行,让它们按数字顺序输出。
// 改用 queueMicrotask 和 setTimeout 包裹它们。
console.log('4 timeout later');
console.log('3 timeout');
console.log('2 microtask');
console.log('1 sync');
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

Node.js 基础中的所有课

自己练习: Express 在线编辑器