主题
event loop 事件循环机制
执行过程
- 将
同步任务
放到执行栈中执行 - 遇到
异步任务
,则放入 Event Table 中注册,并交给其他线程执行,执行完后放入事件队列中 - 将执行栈中的代码
全部执行完毕
事件队列任务
的执行- js 中
- 执行所有
微任务
- 取出
第一个宏任务
执行 - 再
清空微任务队列
(因为有可能宏任务执行完后会产生新的微任务) - 返回到步骤 2,直至事件队列中的任务全部执行完
- 执行所有
node
中- 执行
所有微任务
- 执行
所有宏任务
- 返回到步骤 1,直至事件队列中的任务全部执行完
- 执行
- js 中
js 和 node 不同的举例
jsPromise.resolve().then(data => console.log(1)) setTimeout(() => { console.log(2) Promise.resolve().then(data => console.log(3)) }, 0) setTimeout(() => { console.log(4) }, 0)
- js 的输出为 1 2 3 4
- node 的输出为 1 2 4 3
宏队列和微队列
- 遇到
setTimeout
直接把其放到事件队列中 - 遇到
pormise
,执行 promise 中的代码,到resolve
或reject
后,把then
放到事件队列中(resolve
或reject
后的代码会执行完) - 遇到
await
,执行后面的表达式,执行完后,把 await 后面的代码全部放到事件队列中
node中有所不同
宏队列:setTimeout,setInterval,setImmediate,ajax,dom 操作当他们之间的时间间隔相差10时,谁先谁后都是有可能的
微队列:Promise、async/await、MutationObserver、queueMicrotask、process.nextTick
requestAnimationFrame 和 requestIdleCallback 理论上属于宏任务,但因为还和帧有关,所以实际执行时间不一定按规则走
面试题目与解答
javascript
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
new Promise(resolve => {
console.log('promise1');
resolve();
}).then(() => {
console.log('promise2');
})
}
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0)
async1();
new Promise(resolve => {
console.log('promise3');
resolve();
}).then(() => {
console.log('promise4');
})
console.log('script end');
我的做题过程(拿张纸跟着我做一遍把)
- async1和 async2只是声明,不管,直接看下面的代码
- 看到 console.log('script start'); ,同步代码,把其画到 执行栈 中
- setTimeout,异步代码,把其画到 事件队列 中(画到中间,如果遇到微队列的任务,画到前面)
- 执行 async1,看 async1函数
- 看到 console.log('async1 start'); ,同步代码,把其画到 执行栈 中
- 执行async2(),看到Promise立即执行,所以 console.log('promise1'); 是同步代码,把其画到 执行栈 中
- 看到 resolve() ,then 后面都是异步的,把其画到 事件队列 中(9 resolve() —— 表明这是第9行的 resolve)
- await async2(),await是返回promise对象,即 await async2() 下面的代码全是这个promise的 then 中的代码,所以是异步代码,把其画到 事件队列 中(3 resolve() —— 表明这是第3行的 resolve)
- 看回 19行,Promise立即执行,console.log('promise3'); 是同步代码,把其画到 执行栈 中
- 看到 resolve() ,把其画到 事件队列 中(21 resolve() —— 表明这是第21行的 resolve)
- console.log('script end');,同步代码,把其画到 执行栈 中
- 从 事件队列中 依次执行
- 9 resolve(),console.log('promise2'); ,同步代码,把其画到 执行栈 中
- 3 resolve(),console.log('async1 end'); ,同步代码,把其画到 执行栈 中
- 21 resolve(), console.log('promise4');,同步代码,把其画到 执行栈 中
- setTimeout,console.log('setTimeout');,同步代码,把其画到 执行栈 中
- 结果
- script start
- async1 start
- promise1
- promise3
- script end
- promise2
- async1 end
- promise4
- setTimeout