前言
最近看到了比较多的Promise题目,主要考查的就是对事件循环的一个理解和掌握程度,事件循环的讲解,因为JavaScript是分为同步和异步执行,所以就会出现后面的代码比前面的代码先执行,我们通过几道题目来学习类似的面试题。
宏任务和微任务的执行顺序
这类型的题目我们都需要拆解成三个部分
- 同步执行的代码
- 微任务
- 宏任务
console.log('script start');
setTimeout(function() {
console.log('setTimeout')
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
setTimeout(function() {
console.log('promise1 setTimeout');
}, 0);
})
Promise.resolve().then(function() {
console.log('promise2');
})
console.log('script end');
通过拆分多个步骤来解析执行顺序 定义两个数组 宏任务:[ ] 微任务:[ ]
第一步
console.log('script start')为同步代码直接执行输出script start- 然后遇到了一个定时器,所以需要把定时器中的回调函数添加到宏任务中 宏任务:
[]
[
console.log('setTimeout')
]
- 然后进入一个立即成功的Promise中把这段代码添加到微任务中
[
console.log('promise1');
setTimeout(function() {
console.log('promise1 setTimeout');
}, 0);
]
- 接下来还是一个Promise,同上操作,添加到微任务中
[
console.log('promise1');
setTimeout(function() {
console.log('promise1 setTimeout');
}, 0);
,
console.log('promise2');
]
- 最后
console.log('script end')为同步代码直接执行输出script end
第一次执行结束了,接下来执行微任务中的代码,再执行宏任务的代码
- 首先执行
console.log('promise1');, 遇到定时器就添加到宏任务中
[
console.log('setTimeout')
,
console.log('promise1 setTimeout')
]
- 执行
console.log('promise2'); - 现在微任务队列任务全部执行完毕,宏任务中还有两个任务,依次执行
// 最后我们得到的结果就是
script start
script end
promise1
promise2
setTimeout
promise1 setTimeout
Async/Await
es7中加入了async/await, 是一个语法糖,解决回调地狱问题
await new Promise(reslove => {
resolve('完成')
})
console.log('end')
同等于
new Promise(reslove => {
resolve('完成')
}).then(res => {
console.log('end')
})
可以理解成
await后的Promise成功了之后,后续的代码就放到微任务中就可以了,再结合宏微任务的执行顺序,基本就可以解决大部分Promise输出顺序的面试题,看一个例子吧
console.log('start')
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end') // 这一行代码在async2这个Promise成功后添加到微任务中
}
async function async2() {
console.log('async2 start')
return new Promise(resolve => {
resolve()
console.log('async2 end')
})
}
async1()
- 输出
start async1 start- 执行
async2函数 - 输出
async2 start async2 end- Promise成功 同步代码结束
- 微任务还有一个
async1 end输出完结束