执行下面这段代码,如果和你想的输出顺序一致,那么你可能已经掌握了Js的异步编程,本文对你来说或许没太大帮助。什么,输出顺序和你想的不一样?请往下看:
async function log(x){
console.log(x)
setTimeout(()=>{ console.log('H')},0);
new Promise((resolve,reject)=>{
console.log("G");
resolve();
}).then(()=>{
console.log('J')
})
console.log('I');
}
new Promise((resolve,reject)=>{
console.log('A');
resolve();
}).then(()=>{
console.log('B')
})
console.log('C');
setTimeout(function(){
console.log('D')
},0)
log('E')
console.log('F');
debugger;
执行代码,开始第一轮tick,首先遇到Promise。
- Promise构造函数内部属于宏任务,立即执行,输出A,然后
resolve(),.then()的回调会加入此轮tick尾部 - 输出C
- 遇到定时器,
0秒后将回调函数内的操作加入下一轮tick - 执行
async函数log()- 输出E
- 遇到定时器,
0秒后将回调函数内的操作加入下一轮tick - 遇到
Promise,输出G,.then()的回调会加入此轮tick尾部 - 输出I
- 输出F
- 第一轮
tick结束,执行tick尾部的微任务- 输出B
- 输出J
- 开始第二轮
tick - 输出D
- 输出H
- 事件队列为空,运行完毕
另外,如果async函数内部出现await,那么执行情况是怎样的呢?我们来在async函数中await一个Promise,代码如下:
async function log(x){
console.log(x)
setTimeout(()=>{ console.log('H')},0);
new Promise((resolve,reject)=>{
console.log("G");
resolve();
}).then(()=>{
console.log('J')
})
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
await new Promise((resolve,reject)=>{
console.log('await 1');
resolve()
}).then(()=>{
console.log('await 2');
})
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
console.log('I');
}
你如果执行下代码,会发现在插入await之后,执行顺序发生了很大变化:
- 第一轮
tick - 执行
async函数log()之前的顺序没有改变。输出A、输出C,且B加入此轮tick尾部,D加入下一轮tick。 - 执行
async函数log()- 输出E
- 遇到定时器,
0秒后将回调函数内的操作加入下一轮tick - 遇到
Promise,输出G,.then()的回调会加入此轮tick尾部 - 此时,就到了
await的手中,嘿嘿,不过await的是Promise构造器,输出await 1
await会将当前async函数的执行权交出,等待Promise的状态改变后,再继续执行,并且await返回的是一个Promise。所以我理解为await之后的代码加入了此轮tick尾部(执行验证发现,确实是这样)。
- 输出F
- 第一轮
tick结束,输出tick- 输出B
- 输出J
- 输出
await 2 - 输出I
- 第二轮
tick开始- 输出D
- 输出H
- 事件队列为空,运行完毕