执行下面这段代码,如果和你想的输出顺序一致,那么你可能已经掌握了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
- 事件队列为空,运行完毕