async/await 就是Generator函数的语法糖,只不过它将 * 替换为 async,将 yield 替换为 await,并且它的实现同样离不开Promise。
async 函数返回的是一个 Promise 对象!并且,async 函数的调用并不会造成阻塞,它将内部所有的阻塞都封装在Promise对象中异步执行!
相比Generator函数来说,async/await有如下改进:
(1)内置执行器:async函数和普通函数一样,只需调用就能执行,输出最终结果,不再需要 next 方法。
(2)更好的语义:很明显,async用来声明一个函数是异步的,await表示紧跟在后面的表达式需要等待结果。另外,await 也只能出现在 async函数中。
(3)适用性更广:await命令后面跟的可以是Promise对象或原始类型的值(数值、字符串、布尔值,这时会自动转成Promise对象)。
(4)返回值是Promise对象:async函数的返回值是Promise对象,这比Generator函数的返回值Iterator对象方便对了,你可以用then指定下一步操作。进一步的说,async函数完全可以看做多个异步操作包装成的一个Promise对象,而 await 命令就是内部 then 命令的语法糖。
async function func() {
return new Promise(resolve => {
setTimeout(() => {
resolve('big data');
}, 1000);
});
}
async function test () {
const data = await func();
console.log(data);
}
test(); //1秒后输出'big data'
一、async 函数与 then 命令
因为 async函数返回的是一个 Promise对象,因此可以用then命令来处理这个Promise对象。
1. return返回值
如果在函数中 return 了一个直接量,async 会自动把这个直接量通过 Promise.resolve( ) 封装成Promise对象,async中return语句返回的值,则会被then中的回调函数接收,等于回调的参数值,如下所示:
async function f () {
return 'Yes!';
}
f().then(
v => console.log('操作成功,',v) 回调函数中的参数v的值等于async函数内的return返回值
);
//操作成功,Yes!
补充,Promise.resolve(x) 可以看作是 new Promise( resolve => resolve(x)) 的简写,用于快速封装字面量对象或其他对象,将其封装成 Promise 实例。
2. 抛出错误
async函数内部抛出的错误,会导致返回的Promise对象变成 reject 状态,抛出的错误会被catch中的回调函数接收。
async function f () {
throw new Error('出错了');
}
f().then(
v => console.log('操作成功,',v),
e => console.log('操作失败,',e) //e就是throw的参数‘出错了’
);
//操作失败,Error:出错了
3. Promise的状态变化
async 函数返回的Promise对象,必须等到函数内部所有的await命令后面的Promise对象都执行完,状态才会改变,才会执行then中的回调函数,除非遇到return语句或throw new Error。
二、async 函数与 await 命令
await 表达式的运算结果取决于它要等的东西。
1. return返回值
正常情况下,await 命令后面跟的是一个Promise对象,也就是在等待一个async函数完成。但是await 命令后面可以跟普通函数或直接量。
如果await紧跟的是Promise对象,那await就会阻塞后面代码,等待Promise对象resolve,await的运算结果就是resolve的值;如果不是Promise对象,就直接返回对应的值,不会阻塞。
async function func() {
return await 123; //等同于return 123
}
func().then(
v => console.log(v)
);
//123
2. 抛出错误
await后面跟的是Promise对象时,如果Promise状态为reject,则reject的参数会被catch中的回调函数接收,并且async函数会中断执行。
async function f() {
awayt Promise.reject('出错了');
await Promise.resolve('hello'); //该语句不会执行
}
如果出现1)不想async函数因为reject中断执行 或 2)await后面的异步操作出错,则应该使用 try...catch。
async function f() {
try {
await new Promise((resolve, reject) => {
throw new Error('出错了');
});
} catch(e) {
}
return await('hello');
}
参考资料: