JavaScript的执行
# JavaScript 的执行
首先一个 js 脚本本身对于浏览器而言就是一个宏任务,也是第一个宏任务,而处于其中的代码可能有 3 种:非异步代码、产生微任务的异步代码(promise 等)、产生宏任务的异步代码(settimeout、setinterval 等)。 我们知道宏任务处于一个队列中,应当先执行完一个宏任务才会执行下一个宏任务,所以在 js 脚本中,会先执行非异步代码,再执行微任务代码,最后执行宏任务代码。这时候我们进行到了下一个宏任务中,又按照这个顺序执行。
需要注意的是:微任务总是先于宏任务这个说法不准确,应该是处于同一级的情况下才能这么说。实际上微任务永远是宏任务的一部分,它处于一个大的宏任务内。
# 执行
- 首先我们分析有多少个宏任务
- 在每个宏任务中,分析有多少个微任务;
- 根据调用次序,确定宏任务中的微任务执行次序;
- 根据宏任务的触发规则和调用次序,确定宏任务的执行次序;
- 确定整个顺序。
# 定义宏任务和微任务
我们把宿主发起(浏览器api)的任务称为宏观任务,把 JavaScript 引擎发起的任务称为微观任务。
# 宏任务和微任务的代码
- macro-task 大概包括:
- script(整体代码)
- setTimeout
- setInterval
- setImmediate
- I/O
- UI render
- micro-task 大概包括:
- process.nextTick
- Promise
- Async/Await(实际就是 promise)
- MutationObserver(html5 新特性)
# 例子一
function sleep(duration) {
return new Promise(function (resolve, reject) {
console.log("b");
setTimeout(resolve, duration);
});
}
console.log("a");
sleep(5000).then(() => console.log("c"));
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 例子二
setTimeout(() => {
console.log(1);
});
new Promise((res) => {
console.log(3);
res(2);
}).then((val) => {
console.log(val);
});
console.log(4);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
我们现在要实现一个红绿灯,把一个圆形 div 按照绿色 3 秒,黄色 1 秒,红色 2 秒循环改变背景色
function sleep(duration) {
return new Promise(function (resolve) {
setTimeout(resolve, duration);
});
}
async function changeColor(duration, color) {
document.getElementById("traffic-light").style.background = color;
await sleep(duration);
}
async function main() {
while (true) {
await changeColor(3000, "green");
await changeColor(1000, "yellow");
await changeColor(2000, "red");
}
}
main();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
参考
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
https://juejin.cn/post/6962312899960242213
编辑 (opens new window)
上次更新: 2022/05/30, 17:31:36