JS中的异步函数是什么?什么是JS中的异步和 await?

问题描述 投票:2回答:1

本Q&A旨在对以下问题给出明确的答案。

  • JS中的异步函数是什么,我们什么时候用,怎么用?
  • 哪些是 async, await JS中的关键字,它们与异步函数的关系如何?

按照答案需要以下前提条件。

  • 熟悉JS的异步编程模型。
  • 对ES6 Promise对象的了解
javascript asynchronous promise async-await es6-promise
1个回答
5
投票

介紹

JavaScript有一个异步模型。每当一个异步动作完成后,你往往想在之后执行一些代码。首先回调经常被用来解决这个问题。然而,当对多个异步元素的代码进行编程时,使用回调就会出现一个问题。因为当你把多个回调嵌套在彼此内部时,代码就很难快速维护。这种反模式被称为 回话地狱.

承诺

承诺解决了嵌套回调中出现的许多问题。承诺的一个关键属性是,它们可以很好地用一个 承诺链. 这比回调的语法要干净得多,也更容易处理错误。下面是一个例子。

const randomProm = new Promise((resolve, reject) => {
   if (Math.random() > 0.5) {
     resolve('Succes');
   } else {
     reject('Failure');
   }
  
});

// Promise chain
randomProm
  .then((value) => {
    console.log('inside then1');
    console.log(value);
    return value
}).then((value) => {
    console.log('inside then2');
    console.log(value);
    return value
}).catch((value) => {
    console.log('inside catch');
    console.log(value);
});

异步函数

异步函数是建立在承诺之上的。它们允许更方便地使用承诺。异步函数具有以下属性。

  • async 在一个函数声明表达式之前,将该函数变成一个异步函数。顾名思义async函数是异步执行的。
  • 一个异步函数总是返回一个承诺. 它将任何返回的值包装在 Promise.resolve(returnval). 然而,当一个未捕获的错误在async函数内部被抛出时,它将返回值包裹在 Promise.catch(returnval).
  • 在异步函数中,你可以使用 await 关键字,可以在任何承诺之前使用。await 使JS代码停止执行,直到承诺得到解决,也就是说,在async函数中的任何进一步的代码被执行之前,承诺必须被履行或拒绝。
  • await 要么返回已完成承诺的值,要么在拒绝承诺的情况下抛出一个错误。我们可以使用常规的try-catch来捕获错误。

让我们用一些例子来说明这个问题。

例1:

const randomProm = new Promise((resolve, reject) => {
    if (Math.random() > 0.5) {
        resolve("Succes");
    } else {
        reject("Failure");
    }
});

// async keyword creates an async function which returns a promise 
async function ansyncExample() {

    try {
        const outcome = await randomProm;
        console.log(outcome);
    } catch (error) {
        console.log(error);
    }

    // This return value is wrapped in a promise
    return 'AsyncReturnVal';
}

// ansyncExample() returns a promise, we can call its corresponding then method
ansyncExample().then((value) => {
    console.log(value);
});

console.log('I get executed before the async code because this is synchronous');

例2:

// We can use async in function expressions
const randomProm = async () => {
    if (Math.random() > 0.5) {
        // This value is wrapped in Promise.resolve()
        return "Succes";
    } else {
        // This value is wrapped in Promise.reject()
        throw "Failure";
    }
};

// async keyword creates an async function which returns a promise
async function ansyncExample() {
    // randomProm is async fuction which returns a promise which we can await
    return await randomProm();
}

// ansyncExample() returns a promise, we can call its corresponding then/catch method
ansyncExample()
    .then((value) => {
        console.log("Inside then");
        console.log(value);
    })
    .catch((value) => {
        console.log("Inside catch");
        console.log(value);
    });

console.log("I get executed before the async code because this is synchronous");

什么时候使用异步函数

理论上,你可以在每次使用承诺时都使用async函数。然而当有多个返回承诺的异步操作,并且这些操作相互依赖时,异步函数的威力才真正开始发挥出来。

因为async函数允许我们以同步的方式编写基于异步承诺的代码。代码仍然是异步的,但我们现在可以以同步的方式读取它了. 它比诺言链更容易读取和维护,因此扩展性更好(IMO)。

这里有一个很好的可读性的例子。

async function ansyncExample() {
    try {
        // 3 async operations which depend on each other
        const firstValue = await firstAsyncFunc();
        const SecondValue = await secondAsyncFunc(firstValue);
        const ThirdValue = await thirdAsyncFunc(SecondValue);
    } catch (error) {
        console.log(error);
    }

    return ThirdValue;
}
© www.soinside.com 2019 - 2024. All rights reserved.