2
再谈 js 宏任务与微任务
source link: https://www.yukapril.com/2022/11/05/micro-task.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
再谈 js 宏任务与微任务
之前面试遇到考宏任务、微任务的考题。当时就有一个疑问,如果多个宏任务内,有微任务,那么是执行完毕宏任务、再执行微任务呢,还是如何执行?
之前的文章,见此。
这次模拟下,宏任务 setTimeout
内增加宏任务和微任务。可以先看题试试,下面接着就是答案了。
const p1 = new Promise((resolve) => {
console.log("promise1");
resolve();
});
const p2 = new Promise((resolve) => {
console.log("promise2");
resolve();
});
const p3 = new Promise((resolve) => {
console.log("promise3");
resolve();
});
const p4 = new Promise((resolve) => {
console.log("promise4");
resolve();
});
console.log("start");
setTimeout(() => {
console.log("setTimeout1-run");
setTimeout(() => {
console.log("setTimeout1-setTimeout-run");
});
});
setTimeout(() => {
console.log("setTimeout2-run");
p3.then(() => {
console.log("setTimeout2-promise-run");
});
});
setTimeout(() => {
console.log("setTimeout3-run");
p4.then(() => {
console.log("setTimeout3-promise-run");
});
});
p1.then(() => {
console.log("promise1-run");
});
p2.then(() => {
console.log("promise2-run");
});
console.log("end");
直接贴出答案:
01 promise1
02 promise2
03 promise3
04 promise4
05 start
06 end
07 promise1-run
08 promise2-run
09 setTimeout1-run
10 setTimeout2-run
11 setTimeout2-promise-run
12 setTimeout3-run
13 setTimeout3-promise-run
14 setTimeout1-setTimeout-run
文章代码比较多,可以开两个窗口,左边看代码,右边看分析解释。
- 前 4 个可以看出,Promise 内执行函数不是微任务,而返回 promise 对象调用才是微任务。所以先打印前 4 个
- 随后执行第一个直接打印,输出
start
,这个没有问题 - 执行到到第一个
setTimeout
,内部的代码放置到宏任务队列,即下面代码:() => {
console.log("setTimeout1-run");
setTimeout(() => {
console.log("setTimeout1-setTimeout-run");
});
} - 执行到到第二个
setTimeout
,相应代码放置到宏任务队列 - 执行到到第三个
setTimeout
,相应代码放置到宏任务队列 - 执行到到第一个
promise
,内部的代码放置到微任务队列,即下面代码:() => {
console.log("promise1-run");
} - 执行到到第二个
promise
,相应代码放置到微任务队列 - 执行第二个直接打印,输出
end
- 主线程执行完成,此时微任务 2 个(都是
promise
创建的),宏任务 3 个(都是setTimeout
创建的) - 检查微任务队列(有 2 个),执行微任务(第 6 条内容),输出
promise1-run
- 检查微任务队列(有 1 个),存在任务,执行微任务(第 7 条内容),输出
promise2-run
- 检查微任务队列(无微任务),检查宏任务(有 3 个),执行宏任务(第 3 条内容),输出
setTimeout1-run
,并把内部的setTimeout
补充到宏任务队列 - 检查微任务队列(无微任务),检查宏任务(有 3 个),执行宏任务(第 4 条内容),输出
setTimeout2-run
,并把内部的promise
补充到微任务队列 - 检查微任务队列,此时存在微任务了(第 13 条中刚添加的)!故执行微任务,输出
setTimeout2-promise-run
- 检查微任务队列,无微任务,检查宏任务(有 2 个),执行宏任务(第 5 条内容),输出
setTimeout3-run
,并把内部的promise
补充到微任务队列 - 检查微任务队列,此时又存在微任务了(第 15 条中刚添加的)!故执行微任务,输出
setTimeout3-promise-run
- 检查微任务队列,无微任务,检查宏任务(有 1 个),执行宏任务(第 12 条中添加的),输出
setTimeout1-setTimeout-run
- 主线程、微任务、宏任务均完成,结束
通过上面的例子,可以看出,只要是有微任务,那么它一定是优于宏任务先执行的,简单来说,执行规则为:
Promise
内包裹函数,是同步逻辑,不是异步逻辑。回调的才是then
是微任务;- 每次执行,都要判断当前主线程(同步代码)、微任务、宏任务,并按此顺序执行;
- 执行逻辑中,遇到微任务、宏任务,分别将逻辑按顺序存放到对应的队列中,并按顺序执行。即先放入微任务队列的,后续在执行微任务环节先执行。
–END–
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK