当async、await、promise、promise.then同时存在时,代码该如何执行?
例子一
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
执行过程 顺序执行,log出script start,注册一个宏任务setTimeout
执行async1
执行async1中的log
执行await后的async2
这里需要注意,async2虽然是异步函数,但是在遇到await之前,代码是同步执行的,所以这里会log出async2,执行完之后,没有return,所以返回undefined。此时代码变成了promise.resolve(undefined)。
async function async1() {
console.log('async1 start')
await Promise.resolve(undefined)
console.log('async1 end')
}
await后的函数相当于在promise.then()中,执行,所以现在注册了一个微任务
代码如下
async function async1() {
console.log('async1 start')
var promise = await Promise.resolve(undefined)
promise.then(() => {
console.log('async1 end')
})
}
接着执行同步代码,new Promise中log出promise1,然后注册一个微任务
接着执行同步代码,log出script end,同步代码执行完毕,开始执行微任务
执行第一个微任务,log出async1 end
执行第二个微任务,log出promise2
执行宏任务,log出setTimeout
综上,执行结果是
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
上面代码改为promise为
function async1() {
console.log('async1 start')
new Promise((resolve) => {
console.log('async2');
resolve()
}).then(() => {
console.log('async1 end')
})
}
console.log('script start')
setTimeout(function () {
console.log('setTimeout')
}, 0)
async1();
new Promise(function (resolve) {
console.log('promise1')
resolve()
}).then(function () {
console.log('promise2')
})
console.log('script end')
总结:
new Promise内的代码是同步代码,promise.then()中的代码是异步代码中的微任务,setTimeOut是异步代码中的宏任务,而代码的执行顺序是同步代码 -> 微任务 -> 宏任务。 在async函数中,await之前的代码是同步代码,跟随await的是异步代码,await之后的代码在await返回resolved的状态后才会执行。
小提醒:如果await返回一个promise,只有当promise是resolved的状态时,才会执行后面的代码,如果await后面不是一个promise,会把当前值转化为已经解决的promise,继续执行后面的代码,并且等待处理结果。
async function async1() {
console.log('async1 start')
await promise1()
console.log('async1 end')
}
function promise1() {
return new Promise(() => { // 注意return
console.log('promise');
})
}
如果有return的话,返回的promise是pending状态,后面的console.log就不会执行,没有return的话,相当于返回 undefined,await会包裹一层Promise.resolve(),所以console.log会执行。
例子二
setTimeout(_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
这个例子比较简单
顺序执行,注册一个宏任务
执行new Promise,log出1,同时注册一个微任务
执行同步代码,log出2
执行微任务,log出3
执行宏任务,log出4
所以顺序是
1
2
3
4
后续: 虽然已经做了重点标记,但再次看的时候,还是在async2的地方出了错。原因在于不知道生成器函数在调用next之后,暂停在了哪里,是yield之前?yield中?还是yield后?
经过测试和官网文档,可以确定,在调用next时,会执行yield后面的表达式,执行完后,会暂停
测试用例
function* gen() {
yield new Promise((resolve) => {
console.log('next');
setTimeout(() => resolve(1))
});
console.log('after');
}
var v = gen();
第一次调用next
第二次调用next