学习的时候遇到一个问题
async function getData() {
return await Promise.resolve('I made it!');
}
const data = getData();
console.log(data);
学习的时候看到说await会使得async函数中断,像执行同步代码那样子,直到返回值回来再执行下面的代码,于是乎就觉得await返回的值是一个值,所以上述例子第一眼看上去觉得答案是I made it!
但是答案是Promise {<pending>}
,带着不解,我在控制台上随便试了一波
首先确定一下返回值的问题
async function getData() {
return 'I made it!';
}
const data = getData();
console.log(data);
结果是Promise {<fulfilled>: 'I made it!'}
,这就确定了一点,async函数的返回值会封装成一个promise对象,至于这个promise对象的状态是pending还是fullfilled就取决于具体的返回值了。
再对上面的例子进行修改,确定一下函数内部的await的返回值
async function getData() {
let a = await Promise.resolve('I made it!');
console.log(a)
return a
}
const data = getData();
console.log(data);
结果是
和印象里的没错,await是会返回promise对象的值,但是这个顺序又让我有疑问了,按理说应该是先执行getData()函数,再执行log,那不是应该先是打印I made it!
再打印Promise {<pending>}
吗?带着这个疑问,我再修改一下例子
async function getData() {
console.log(111)
let a = await Promise.resolve('I made it!');
console.log(222)
console.log(a)
return a
}
const data = getData();
console.log(data);
结果是:
根据输出来推测一波,首先执行getData()函数,getData()函数是一个async函数,返回值是await声明的promise对象;再执行getData()的时候,111
在await之前,最先被执行,所以最先被打印;接着到await语句,前面说过,这时候函数内部中断,直到promise返回,所以下面的222
和a的值
的打印都被延迟了,总的来说就是,那些都被放进异步的进程里面了,所以此时函数内部的同步进程以已经执行到了return并把当时还未返回值的promise(pengding状态)送给了data,这时候getData()的同步进程已经执行完(看到后面再回头看这里就发现漏洞了,其实这时候getData函数被堵塞住了,而async函数无论有无return都是会返回一个promise对象,所以此时getdata函数并未执行完,但是确实是将内部操作放到异步去执行,然后紧接着执行主动进程的任务),外界的代码接下来打印data,由于异步进程肯定不够主动进程解析代码快,所以此时data的状态还是pendding,就打印了Promise {<pending>}
,后续就是getdata内部的异步进程开始执行,打印222
,打印a的值
;
我们进一步验证一下上面的推测,如果再执行完getdata之后先延迟1s再打印data,结果应该是
111
222
I made it !
promise{<fullfilled>}
async function getData() {
console.log(111)
let a = await Promise.resolve('I made it!');
console.log(222)
console.log(a)
return a
}
const data = getData();
setTimeout(()=>console.log(data),1000)
结果是符合预期的
当然,上述的同步异步进程是我的一种猜测,还是得找官方文档,
1.await 表达式会暂停整个 async 函数的执行进程并出让其控制权,只有当其等待的基于 promise 的异步操作被兑现或被拒绝之后才会恢复进程。
2.async 函数的函数体可以被看作是由 0 个或者多个 await 表达式分割开来的。从第一行代码直到(并包括)第一个 await 表达式(如果有的话)都是同步运行的。这样的话,一个不含 await 表达式的 async 函数是会同步运行的。然而,如果函数体内有一个 await 表达式,async 函数就一定会异步执行。
3.在 await 表达式之后的代码可以被认为是存在在链式调用的 then 回调中,多个 await 表达式都将加入链式调用的 then 回调中,返回值将作为最后一个 then 回调的返回值。
这么看来,还需要验证一个例子,这个是为了验证return是在await拿到返回值之前还是之后
async function getData() {
console.log(111)
let a = await Promise.resolve('I made it!');
console.log(222)
console.log(a)
return 123
}
const data = getData();
console.log(data);
根据答案可以知道,return是在await之后,和官方文档一样,执行到await会中止同步进程,进入异步进程直到异步进程结束再最后返回,但是我们也知道了一点,如果在async函数内部的异步进程没有结束,没有把主动权交还给主动进程,此时的async函数的返回值(无论有无return)都是pending状态的promise对象,但是有一点就是同步异步进程不会影响,否则如果getData函数卡在了await的异步进程,那为什么外面打印data会顺利进行呢?答案就是前面分析的异步进程和主动进程不会影响,当await执行异步操作的时候,外面的同步操作也在进行
总结: