事件循环(消息队列)
为啥要用事件循环?防止主线程阻塞 js是单线程的脚本语言,在同一时间,只能做同一件事。
一个渲染任务过来了。 同步任务:立刻能处理的任务。 js运行时 会立刻放进 执行栈 中 异步任务:无法立即处理的任务。任务的回调会被放进 消息队列 。
如何处理渲染任务? 主线程循环:主线程不断循环,执行 执行栈中的代码。 执行完毕,才检查消息队列中是否有任务;有就放进去执行,没有就休息。
消息队列
- 微队列:
async awaitPromise.then()、Promise.catch()、Promise.finally()new Promise(resolve, reject){ }的resolve或reject的处理函数- MutaionObserver( ) 监视DOM变化
- 交互队列(宏任务-高优先级):
UI 渲染:requestAnimationFrame在渲染前执行,属于宏任务但优先级高于普通任务用户事件:addEventListener(‘‘onclick’’, handleClick() )网络请求:fetch( ) 、 axois()- 跨文档通信: window.postMessage( )
- 文件读写:fs.readFile(Node.js)
- 延迟队列(宏任务-低优先级):setTimeout( ) 与 setInteval( )
避坑指南
- 牢记微任务优先:任何
Promise的.then()回调都会在当前同步代码执行完毕后立即执行。 - 宏任务必须等待:
setTimeout、setInterval等回调属于宏任务,必须等到所有微任务执行完毕后才会执行。 - 嵌套的微任务按顺序执行:即使微任务嵌套在另一个微任务中,它们仍会按添加顺序依次执行。
- 链式调用中的返回值:返回
Promise会影响后续.then()的执行时机。 .then()要等到前面执行完才放入微任务
题一
console.log('start');
setTimeout(() => console.log('timeout1'), 0);
Promise.resolve()
.then(() => {
console.log('promise1');
setTimeout(() => console.log('timeout2'), 0);
return Promise.resolve().then(() => console.log('promise2'));
})
.then(() => console.log('promise3')); `.then要等到前面执行完才执行`
console.log('end');
--------------------------
执行栈
console.log('start')
console.log('end')
console.log('promise1')
console.log('promise2')
console.log('promise3')
console.log('timeout1')
console.log('timeout2')
微
() => {
console.log('promise1');
setTimeout(() => console.log('timeout2'), 0);
return Promise.resolve().then(() => console.log('promise2'));
})
.then(() => console.log('promise3'));
-------------------------------
() => console.log('promise2')
() => console.log('promise3')
宏
() => console.log('timeout1')
() => console.log('timeout2')
题二
await后面 相当于 Promise.resolve().then() 要放入微任务
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end'); `await后面 相当于 promise.then()`
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
async1();
new Promise(resolve => {
console.log('promise1');
resolve();
console.log('after promise1');
}).then(() => console.log('promise2'));
console.log('script end');
--------------------------------
// 执行栈
console.log('script start')
console.log('async1 start')
console.log('async2')
console.log('promise1');
console.log('script end')
console.log('async1 end')
console.log('promise2')
console.log('setTimeout')
// 微任务
()=> console.log('async1 end')
() => console.log('promise2')
// 宏任务
() => console.log('setTimeout')
题三
宏任务中有微任务,立刻执行微任务
await后面的代码,一定要跟在后面写 ).then(()=>{ xxx })
async function async1() {
console.log(1);
await async2(); `await后面的代码,一定要跟在后面写 ).then(()=>{ xxx })`
console.log(2);
setTimeout(() => console.log(3), 0);
}
async function async2() {
console.log(4);
await Promise.resolve().then(() => {
console.log(5);
setTimeout(() => console.log(6), 0);
});
}
console.log(7);
setTimeout(() => {
console.log(8);
Promise.resolve().then(() => console.log(9));
}, 0);
async1();
Promise.resolve().then(() => {
console.log(10);
setTimeout(() => console.log(11), 0);
});
console.log(12);
-----------------
// 执行栈
console.log(7);
console.log(1);
console.log(4);
console.log(12)
console.log(5)
console.log(10)
console.log(2)
console.log(8)
console.log(9)
console.log(6)
console.log(11)
console.log(3)
// 微
() => {
console.log(5);
setTimeout(() => console.log(6), 0);
}).then(()=>{
console.log(2);
setTimeout(() => console.log(3), 0);
})
() => {
console.log(10);
setTimeout(() => console.log(11), 0);
}
()=>{
console.log(2);
setTimeout(() => console.log(3), 0);
}
//宏
console.log(8);
Promise.resolve().then(() => console.log(9)); `宏任务中有微任务,立刻执行微任务`
() => console.log(6)
() => console.log(11)
() => console.log(3)