大家好,这篇文章让我们来了解一下 async/await 语法糖的用法以及实现原理。
async/await 语法糖其实就是为了简化 promise.then 繁琐的链式调用而产生的,为了让代码更简洁,书写更方便。
一、async的用法以及功能点:
- async 函数的返回值是一个 promise 对象;
- 返回的 promise 对象的结果由 async 函数中的返回值决定,有三种情况:
- 返回值是一个新的 promise 对象;
- 返回值是非 promise 对象的任意值;
- throw抛出错误;
上面的第2个功能点熟悉不?看过我之前写的 “手写promise原理系列” 篇章的小伙伴应该都知道,这里 async 函数中的返回值其实跟 promise.then 方法的返回值描述规则是一模一样的。
想了解更多,请回看 手写promise原理系列二:手写promise的关键逻辑梳理,promise用法原理 中的第四个知识点:promise.then() 返回的 promise 对象的结果由什么决定?
下面,让我们用代码来加深一下印象:
(1)async 函数内部无返回值。
async function asyncFn() { };
let p = asyncFn();
console.log(p);
(2)async 函数内部返回成功的 promise 对象以及失败的 promise 对象
async function asyncFnResolve() {
return new Promise((resolve, reject) => {
resolve("OK");
});
};
async function asyncFnReject() {
return new Promise((resolve, reject) => {
reject("NO");
});
};
let p1 = asyncFnResolve();
let p2 = asyncFnReject();
console.log(p1);
console.log(p2);
(3)async 函数内部返回一个普通值。
async function asyncFn() {
return "111";
};
let p = asyncFn();
console.log(p);
(4)async 函数内部抛出异常,返回一个失败的 promise 对象。
async function asyncFn() {
throw "error";
};
let p = asyncFn();
console.log(p);
二、await 的用法以及功能点:
- await 语法只能在 async 函数体中 或者 模块的顶级主体中使用,否则报错;
- await 右侧的表达式一般为 promise 对象,但也可以是其他值;
- 如果 await 右侧是 promise 对象,则 await 返回的是 promise 成功的值;
- 如果 await 后面跟随的 promise 对象失败了,则使用 try…catch… 语句捕获错误;
- 如果表达式是其他值,直接将此值作为 await 的返回值;
- async 函数中遇到 await 语句时会暂停执行,等待获取状态结果,await 语句后面的代码会放到微任务队列等待同步任务执行完毕之后再继续执行
(1)await 不在 async 函数中使用时报错
fn();
function fn(){
await "111";
}
报错信息译文为:未捕获的语法错误:await仅在异步函数和模块的顶级主体中有效
那什么是模块的顶级主体呢?可以参考这篇文章 顶级 await 在 Node.js 模块中可用啦!
(2)await 后面跟普通值
asyncFn()
async function asyncFn(){
let p = await "111";
console.log(p); // "111"
}
(3)await 后面跟成功的 promise 对象
asyncFn()
async function asyncFn(){
let p = await new Promise((resolve, reject) => {
resolve("111");
});
console.log(p); // "111"
}
(4)await 后面跟失败的 promise 对象
asyncFn()
async function asyncFn(){
let p = await new Promise((resolve, reject) => {
reject("NO");
});
console.log(p); // 报错
}
需要使用 try…catch… 捕获错误,如下:
asyncFn()
async function asyncFn(){
try {
await new Promise((resolve, reject) => {
reject("NO");
});
} catch (err) {
console.log(err); // "NO"
}
}
三、async/await的实用案例
比方说,我们要调用以下三个接口获取数据,如下:
let a = "https://www.baidu.com";
let b = "https://www.taobao.com";
let c = "https://www.jd.com";
使用 promise 方式:
let p = new Promise((resolve, reject) => {
let data = fetch(a);
resolve(data);
});
p.then(res1=> {
console.log(res1);
return new Promise((resolve, reject) => {
let data = fetch(b);
resolve(data);
});
}).then(res2 => {
console.log(res2);
return new Promise((resolve, reject) => {
let data = fetch(c);
resolve(data);
});
}).then(res3 => {
console.log(res3);
})
上面代码中 fetch 调用接口本身返回的就是 promise 对象,代码示例中 fetch 外面又包了一层 promise 是为了演示 promise.then 链式调用的繁琐性,因为真实的项目中代码会更多,勿怪。
fetch 接口调用的返回值:
使用 async/await 方式:
getData();
async function getData(){
let res1 = await fetch(a);
console.log(res1);
let res2 = await fetch(b);
console.log(res2);
let res3 = await fetch(c);
console.log(res3);
}
上面的两种方式书写代码都是异步获取接口的返回值,但我就问你,async/await 的使用方式,简洁不简洁,优雅不优雅。
四、async/await的实现原理
请参考这篇文章:async/await原理揭秘