0

await 关键词

 11 months ago
source link: https://www.myfreax.com/javascript-async-await/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
JavaScript async / await 关键词

JavaScript async / await 关键词

在本教程中,您将学习如何使用 JavaScript   async / await关键词编写异步代码。

请注意,要了解  async / await 工作原理,您需要了解 promise 的工作原理。

JavaScript async / await 关键字介绍

以前,处理异步操作,通常是使用回调函数。但是,当你嵌套很多回调函数时,代码就会更难维护。你最终会遇到一个臭名昭著的问题,称为回调黑洞。

假设您需要按以下顺序执行三个异步操作:

  1. 从数据库中获取一个用户。
  2. 从 API 获取用户的服务。
  3. 根据服务器提供的服务计算服务费用。

以下函数说明了这三个任务。请注意,我们使用 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关键字编写看起来像同步代码的异步代码。

微信公众号

支付宝打赏

myfreax 淘宝打赏

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK