宏任务微任务同步异步执行顺序
JS 分为同步任务和异步任务
同步任务在主线程上执行
异步任务放在主线程之外的一个任务队列
主线程执行完毕后,读取任务队列的内容
宏任务(macro)task
当前主线程上执行的就是一个宏任务。例: script 的代码、setTimeout、setInterval、postMessage等。
微任务microtask
例:Promise.then、await后面的代码。
在执行当前宏任务时(同步执行时),遇到 setTimeout 会把它放到宏任务队列Event Queue。遇到Promise.then会放到微任务队列Event Queue。
这是两个不同的 Event Queue
当前 宏任务 执行完毕后,会先查看微任务队列,如果有任务,优先执行,否则执行下一个宏任务。
首先执行 宏任务 => 微任务的Event Queue => 宏任务的Event Queue
console.log('同步-0.1')
Promise.resolve().then(() => {
console.log('P-1.1')
Promise.resolve().then(() => { // 新加行
console.log('P-2.1') // 新加行
Promise.resolve().then(() => { // 新加行
console.log('P-3.1') // 新加行
}) // 新加行
}) // 新加行
})
setTimeout(() => {
console.log('S-1.1')
});
Promise.resolve().then(() => {
console.log('P-1.2')
})
setTimeout(() => {
console.log('S-1.2')
});
console.log('同步-0.2')
执行结果如下:
同步-0.1
同步-0.2
P-1.1
P-1.2
P-2.1
P-3.1
S-1.1
S-1.2
所以 promise.then 会先于 setTimeout执行。**无论Promise套用多少层,都会在下一个setTimeout之前执行。**多层Promise嵌套,嵌套的会排在没有嵌套的Promise后面
案例
async function async1() {
console.log("async1 start");
// 第三个宏任务
await setTimeout(() => {
console.log("async1 end");
new Promise(function (reslove) {
reslove();
}).then(function () {
// 宏任务中的微任务
console.log("promise4");
});
}, 0);
async2();
}
async function async2() {
console.log("async2");
}
//--------------------------------上面是函数的声明
console.log("script start");
// 第二个宏任务
setTimeout(() => {
console.log("setTimeOut");
new Promise(function (reslove) {
reslove();
}).then(function () {
// 宏任务中的微任务
console.log("promise3");
});
}, 0);
async1();
new Promise(function (reslove) {
console.log("promise1");
reslove();
}).then(function () {
console.log("promise2");
});
console.log("script end");
执行顺序
script start
async1 start
promise1
script end
async2
promise2
setTimeOut
promise3
async1 end
promise4
- 宏任务是主流,当js开始被执行的时候,就是开启一个宏任务,在宏任务中执行一条一条的指令;
- 宏任务可以同时有多个,但会按顺序一个一个执行;
- 每一个宏任务,后面都可以跟一个微任务队列,如果微任务队列中有指令或方法,那么就会执行;如果没有,则开始执行下一个宏任务,直到所有的宏任务执行完为止,微任务相当于宏任务的小尾巴;
- 为什么有了宏任务,还会有微任务存在?因为宏任务太占用性能,当需要一些较早就准备好的方法,排在最后才执行的时候,又不想新增一个宏任务,那么就可以把这些方法,一个一个的放在微任务队列里面,在这个宏任务中的代码执行完后,就会执行微任务队列。