事件循环
本课属于 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 表示在微任务完成后尽快运行,而不是在它们之前运行。定时器按延迟时间的顺序触发;延迟相同时,先设置的定时器先触发。
挑战
简单Node 会按固定顺序运行代码。先运行普通语句,然后运行微任务,例如 Promise 回调,最后运行计时器。利用这个顺序,让四行内容按数字顺序打印出来,同时不移动它们。
order.js 中的四行内容会从 4 到 1 打印出来。不要移动或重新排列这些行,而是把其中三行分别包装起来,让它们稍后运行。
- 保持
console.log('1 sync')不变。普通代码会先运行。 - 用
queueMicrotask包装2 microtask这一行,让它在普通代码之后立即运行。 - 分别用各自的
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');
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
Node.js 基础中的所有课
自己练习: Express 在线编辑器