
JavaScript async / await 关键词
在本教程中,您将学习如何使用 JavaScript async / await关键词编写异步代码
在本教程中,您将学习如何使用 JavaScript async / await关键词编写异步代码。
请注意,要了解 async / await 工作原理,您需要了解 promise 的工作原理。
JavaScript async / await 关键字介绍
以前,处理异步操作,通常是使用回调函数。但是,当你嵌套很多回调函数时,代码就会更难维护。你最终会遇到一个臭名昭著的问题,称为回调黑洞。
假设您需要按以下顺序执行三个异步操作:
- 从数据库中获取一个用户。
- 从 API 获取用户的服务。
- 根据服务器提供的服务计算服务费用。
以下函数说明了这三个任务。请注意,我们使用 setTimeout() 函数来模拟异步操作。
function getUser(userId, callback) {
console.log('Get user from the database.');
setTimeout(() => {
callback({
userId: userId,
username: 'john'
});
}, 1000);
}
function getServices(user, callback) {
console.log(`Get services of ${user.username} from the API.`);
setTimeout(() => {
callback(['Email', 'VPN', 'CDN']);
}, 2 * 1000);
}
function getServiceCost(services, callback) {
console.log(`Calculate service costs of ${services}.`);
setTimeout(() => {
callback(services.length * 100);
}, 3 * 1000);
}下面展示嵌套的回调函数:
getUser(100, (user) => {
getServices(user, (services) => {
getServiceCost(services, (cost) => {
console.log(`The service cost is ${cost}`);
});
});
});输出:
Get user from the database.
Get services of john from the API.
Calculate service costs of Email,VPN,CDN.
The service cost is 300为了避免这种回调黑洞问题,ES6 引入允许您以更易于管理的方式编写异步代码的 Promise。
首先,您需要在每个函数返回一个 Promise:
function getUser(userId) {
return new Promise((resolve, reject) => {
console.log('Get user from the database.');
setTimeout(() => {
resolve({
userId: userId,
username: 'john'
});
}, 1000);
})
}
function getServices(user) {
return new Promise((resolve, reject) => {
console.log(`Get services of ${user.username} from the API.`);
setTimeout(() => {
resolve(['Email', 'VPN', 'CDN']);
}, 2 * 1000);
});
}
function getServiceCost(services) {
return new Promise((resolve, reject) => {
console.log(`Calculate service costs of ${services}.`);
setTimeout(() => {
resolve(services.length * 100);
}, 3 * 1000);
});
}然后,您将 Promise 进行链式调用:
getUser(100)
.then(getServices)
.then(getServiceCost)
.then(console.log);ES2017 引入了构建在 promises 之上的 async / await 关键字,允许您编写看起来更像同步代码并且更具可读性的异步代码。从技术上讲,async / await 是 promise 的语法糖。
如果一个函数 f 返回一个 Promise,你可以把 await 关键字放在函数调用的前面,像这样:
let result = await f();await 将等待从 f() 函数返回的 Promise。关键字 await 只能在函数内部使用。
下面定义一个 async 函数,依次调用这三个异步操作:
async function showServiceCost() {
let user = await getUser(100);
let services = await getServices(user);
let cost = await getServiceCost(services);
console.log(`The service cost is ${cost}`);
}
showServiceCost();如您所见,异步代码现在看起来像同步代码。让我们深入了解 async / await 关键字。
async 关键词
async 关键字允许您定义处理异步操作的函数。要定义 async 函数,请 async 关键字放在 function 关键字前面,如下所示:
async function sayHi() {
return 'Hi';
}异步函数通过事件轮询异步执行。它总是返回一个 Promise.
在此示例中,因为 sayHi() 函数返回一个 Promise,您可以像下面一样的 方式使用它,如下所示:
sayHi().then(console.log);您还可以从 sayHi() 函数显式返回一个 Promise,如以下代码所示:
async function sayHi() {
return Promise.resolve('Hi');
}效果是一样的。
除了普通函数外,您还可以在函数表达式使用 async 关键字:
let sayHi = async function () {
return 'Hi';
}箭头函数:
let sayHi = async () => 'Hi'; 类的方法:
class Greeter {
async sayHi() {
return 'Hi';
}
}await 关键词
您使用 await 关键字等待 Promise 以解决或拒绝状态解决。您只能在 async 函数内部使用 await 关键字:
async function display() {
let result = await sayHi();
console.log(result);
}在此示例中,await 关键字指示 JavaScript 引擎在显示消息之前等待 sayHi() 函数完成。
请注意,如果您在async函数外部使用await,则会抛出错误。
错误处理
如果 await promise 已经得到解决,则返回结果。然而,当 promise 被拒绝时,将 await promise 抛出一个错误,就像有一个 throw 声明一样。
以下代码:
async function getUser(userId) {
await Promise.reject(new Error('Invalid User Id'));
}与此相同:
async function getUser(userId) {
throw new Error('Invalid User Id');
}在实际场景中,promise 抛出错误需要一段时间。
您可以使用 try...catch 语句来捕获 Promise 的错误,也可以是 throw 的错误:
async function getUser(userId) {
try {
const user = await Promise.reject(new Error('Invalid User Id'));
} catch(error) {
console.log(error);
}
}可以捕获由一个或多个 await promise 引起的错误:
async function showServiceCost() {
try {
let user = await getUser(100);
let services = await getServices(user);
let cost = await getServiceCost(services);
console.log(`The service cost is ${cost}`);
} catch(error) {
console.log(error);
}
}结论
在本教程中,您学习如何使用 JavaScript async / await关键字编写看起来像同步代码的异步代码。





