浏览器的宏任务与微任务
浏览器的宏任务与微任务
本文写于 2022 年 07 月 22 日
什么是宏任务、微任务
JavaScript 中用来存储待执行的回调函数的队列包含 2 个不同特定的列队:
- 宏列队:用来保存待执行的宏任务
- 定时器回调 / DOM 事件回调 / AJAX 回调(fetch 基于 Promise,所以是微任务)
- 微列队:用来保存待执行的微任务
- Promise 的回调 / MutationObserver 的回调
执行顺序
- 首先必须先执行所有的初始化同步任务
- 然后会检查微任务队列,并将其清空
- 接着取出第一个宏任务
- 当该宏任务执行完成,会检查其中的微任务队列,如果为空则直接执行下一个宏任务;如果不为空,则依次执行微任务,执行完成才去执行下一个宏任务
举个例子:
setTimeout(() => console.log(3));
Promise.resolve().then(() => console.log(2));
console.log(1);
这段代码会依次输出 1、2、3,应该能很好的体现出上面所说的几点。
关于第四点可能有些复杂,我们用一个复杂点的例子来说明:
setTimeout(() => {
console.log(3);
Promise.resolve().then(() => console.log(4));
});
setTimeout(() => console.log(5));
Promise.resolve().then(() => console.log(2));
console.log(1);
该例子也会顺序输出:1、2、3、4、5。
任务的间隙能进行页面渲染吗?
我们先忽略第一次清空微任务队列的流程,浏览器的事件循环大体如下:
宏任务 * 1 => 微任务清空 => 页面渲染
可以看到,在每一个宏任务之后,会尝试清空微任务队列,之后便会进行页面渲染。
这个时候我们思考一个问题:任务过多会影响页面渲染吗?
如果假设单个任务的耗时都不长,那么:
- 如果宏任务过多,完全不会影响页面渲染
- 如果微任务过多,会影响到页面渲染
但是,我们可以尝试往微任务队列塞很多任务,发现好像并没有卡死我们的页面,只是稍微卡顿了一点点而已。
这是因为浏览器也考虑到完全卡死的可能性,所以限制了单次微任务执行的最大次数,默认为 1000 次。
(完)
作者:几乎一米八的徐某某
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。