关于async和await
发现问题
某天在牛客上刷到这样一道题:
async function getData() {
return await Promise.resolve('I made it!');
}
const data = getData();
console.log(data);
问输出结果是什么?我想这也太简单了,肯定是返回一个成功状态的 Promise 啊,一看答案我傻了,居然是一个未解决的 Promise.
最后我好好想了想,之前的理解一直是错的。看了几篇大牛的文章,我学废了
问题分析
看回上面那段代码,async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数。 当函数执行的时候,一旦遇到 await 就会先返回,等到触发的异步操作完成,再接着执行函数体内后面的语句。但是最重要的一点是异步函数 async 始终返回一个 promise。其实这段代码这样写可能更好理解:
async function getData() {
const res = await Promise.resolve('I made it!');
return res;
}
const data = getData();
console.log(data);
当调用getData()
的时候,遇到了await
那么就会暂停在这一行,等待后面的Promise
返回结果,getData()
会先返回,此时返回的肯定是一个Promise
,而且是等待状态的。接着执行调用getData()
之后(async
函数调用不会造成阻塞,它内部所有的阻塞都被封装在一个 Promise
对象中异步执行)的代码,那么这行代码console.log(data)
便会紧跟着执行,此时打印的结果肯定是一个处于等待状态的Promise
。
data.then((res) => console.log(res)); // I made it!
这段代码可能也会让人困惑:
async function getData() {
console.log('async执行开始');
return await Promise.resolve('123');
}
const data = getData();
console.log(data);
const c = data.then((res) => {
console.log(res);
});
console.log(c); // 这里也打印的是一个等待状态的Promise
其实是一样的,分析以下这段代码的执行顺序:调用 getData(),打印async执行开始
,遇到 await,先返回。打印 data,一个等待状态的 Promise,先执行同步代码,打印 c,结果一样。返回去执行异步任务,先清掉所有微任务,async 返回了成功状态的 Promise 且参数为123
,接着执行 then 里面的代码,打印出123
备注
async
函数和普通 函数没有什么不同,他只是表示这个函数里有异步操作的方法,并返回一个 Promise
对象 翻译过来其实就是:
// async/await 写法
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
// Promise 写法
async function async1() {
console.log('async1 start');
// 如果传入的参数是Promise对象,则参数的结果决定了Promise.resolve()的结果
Promise.resolve(async2()).then(() => console.log('async1 end'));
}
async function async2() {
console.log('async2');
}
显然,await
后面的代码,实际上相当于Promise
中then
里面的代码
await
会暂停代码在该行上,直到 promise
完成,然后返回结果值。在暂停的同时,其他正在等待执行的代码就有机会执行了。
如果在函数中 return
一个直接量,async
会把这个直接量通过 Promise.resolve()
封装成 Promise
对象。
还有一点就是如果 async 函数没有返回值,又该如何?很容易想到,它会返回 Promise.resolve(undefined)