昨天我老师发给我一段代码,我兴致勃勃当然觉得没问题了,于是我就推演了一下运行结果,结果是疯狂打脸。我拿着我的猜想和结论,去问我的老师,结果我的大脑好像停止了运行,离正确结果越来越远,我沉思了一会儿,我还是先去复盘一下相关内容吧。
宏任务和微任务是怎么执行的
注意以下几点:
- Promise 优先于 setTimeout 宏任务,所以 setTimeout 回调会最后执行;
- Promise 一旦被定义就会立即执行;
- Promise 的 resolve 和 reject 是异步执行的回调。所以 resolve() 会被放到回调队列中,在主函数执行完和 setTimeout 之前调用;
- await 执行完后,会让出线程。async 标记的函数会返回一个 Promise 对象;
例1
setTimeout(function(){
console.log('1');
});
new Promise(function(resolve){
console.log('2');
resolve();
}).then(function(){
console.log('3');
}).then(function(){
console.log('4')
});
console.log('5');
- 队列开始,迎面遇见setTimeout,放入宏任务队列中;
- 遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出:
'2';- 而Promise.then中的回调是异步的,所以依次把它们放入微任务队列中;
- 遇到同步任务console.log('5');,输出:
'5',主线程中同步任务执行完;- 提取微任务队列到主线程,依次输出:
'3'、'4',微任务队列清空;- 提取宏任务队列到主线程,输出:
'1',宏任务队列为空;- 队列结束;
例2
setTimeout(()=>{
new Promise(resolve =>{
resolve();
}).then(()=>{
console.log('test');
});
console.log(4);
});
new Promise(resolve => {
resolve();
console.log(1)
}).then(() => {
console.log(3);
Promise.resolve().then(() => {
console.log('before timeout');
}).then(() => {
Promise.resolve().then(() => {
console.log('also before timeout')
})
})
})
console.log(2);
- 队列开始,迎面又遇见setTimeout,放入宏任务队列中;
- 遇到new Promise,new Promise在实例化的过程中所执行的代码都是同步进行的,所以输出:
'1';- 而Promise.then中的回调是异步的,所以依次把它们放入微任务队列中;
- 继续执行,遇到同步任务console.log('2'),输出:
'2',主线程中同步任务执行完成;- 提取微任务队列到主线程,输出:
'3',而后微任务队列中又有微任务,Promise.resolve().then(微任务a).then(微任务b)依次放入微任务队列中;- 依次提取微任务队列到主线程,提取微任务a,输出:
'before timeout'- 提取微任务b,微任务b又注册了一个任务c,加入微任务队列;
- 提取微任务队列到主线程,提取微任务c,输出:
'also before timeout',微任务队列清空;- 从宏任务队列提取微任务到主线程,此时任务中又注册了一个微任务d,将其放在微任务队列,迎面输出:
'4',宏任务队列清空;- 提取微任务队列d到主线程,输出:
'test',微任务队列清空;
例3
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(()=>{
console.log('setTimeout');
},0)
async1();
new Promise((resolve)=>{
console.log('promise1');
resolve();
}).then(()=>{
console.log('promise2');
});
console.log('script end');
//script start
//async1 start
//async2
//promise1
//script end
//async1 end
//promise2
//setTimeout
- 队列开始,前两个是异步,迎面输出:
'script start';- 遇到setTimeout,挂起console.log('setTimeout');,加入宏任务队列;
- 调用async1(),输出:
'async1 start',遇到await(依赖async2()执行结果,输出:'async2'),将console.log('async1 end');挂起放入微任务队列;- 执行Promise,输出:
'promise1',回调.then()是异步,所以将console.log('promise2');挂起放入微任务队列;- 执行同步任务console.log('script end');,输出:
'script end',主线任务结束;- 提取微任务队列到主线程,依次输出:
'async1 end'、'promise2',微任务队列清空;- 提取宏任务队列到主线程,输出:
'setTimeout',宏任务队列清空;