且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

JavaScript 中的异步函数是什么?什么是“异步"?和“等待"在 JavaScript 中?

更新时间:2022-04-17 22:30:28

Intro

JavaScript 有一个异步模型.每当异步操作完成时,您通常想在之后执行一些代码.第一次回调是经常用来解决这个问题.但是,当使用多个异步元素编写代码时,使用回调会出现问题.因为当您将多个回调嵌套在彼此内部时,代码变得难以快速维护.这种反模式称为回调地狱.

Promise 解决了嵌套回调中出现的许多问题.承诺的一个关键特性是它们可以使用承诺链很好地链接在一起.这允许比回调更简洁的语法和更容易的错误处理.下面是一个例子:

Promises solved many of the issues that appeared in nested callbacks. A key property of promises are that they can be nicely chained together using a promise chain. This allows for much cleaner syntax than callbacks and easier error handling. Here is an example:

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);
});

异步函数建立在 Promise 之上.它们允许更方便地使用 Promise.异步函数具有以下属性:

Asynchronous functions are built on top of promises. They allow a more convenient use of Promises. Asynchronous functions have the following properties:

  • async 在函数声明/表达式将函数转换为异步函数之前.顾名思义,异步函数是异步执行的.
  • 异步函数总是返回一个承诺.它将任何返回值包装在 Promise.resolve(returnval) 中.但是,当异步函数内抛出未捕获的错误时,它会将返回值包装在 Promise.catch(returnval) 中.
  • 在异步函数中,您可以使用 await 关键字,该关键字可以在任何承诺之前使用.await 使 JS 代码停止执行,直到 promise 完成.即,在执行异步函数中的任何其他代码之前,必须履行或拒绝承诺.
  • await 要么返回已履行的承诺的值,要么在拒绝承诺的情况下抛出错误.我们可以使用常规的 try-catch 来捕获错误.
  • async before a function declaration/expression turns the function into an async function. As the name suggests async function are executed asynchronously.
  • An async function always returns a promise. It wraps any returned value in Promise.resolve(returnval). However, when an uncaught error is thrown inside the async function it wraps the return value in Promise.catch(returnval).
  • Inside async functions you can use the await keyword which can be used before any promise. await makes JS code execution stop until the promise is settled. i.e. The promise has to be either fulfilled or rejected until any further code inside the async function is executed.
  • await either returns the value of the fulfilled promise, or throws an error in the case of a rejected promise. We can use regular try-catch to catch the error.

让我们用一些例子来澄清这一点:

Let's clarify this with some examples:

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');

// 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");

理论上,每次使用 promise 时都可以使用 async 函数.然而,当有多个异步操作返回 promise 并且相互依赖时,异步函数的威力才真正开始发挥作用.

In theory you could use async function everytime when you are using a promise. However the power of async functions really starts to shine when there are multiple async operations that return promises and which depend on each other.

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

Because async function allow us to write asynchronous promise based code in a synchronous manner. The code is still asynchronous but we can now read it in a synchronous manner. It is more easily read and maintained than promise chains and thus scales better (IMO).

这是一个很好的可读性的例子:

Here is an example of this nice readability:

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;
}