JavaScript 中的异步函数是什么?JavaScript 中的 "async" 和 "await" 是什么?

6

本问答旨在清晰回答以下问题:

  • JavaScript 中的异步函数是什么,何时以及如何使用它们?
  • JavaScript 中的 asyncawait 关键字是什么,它们与异步函数有何关系?

为了理解答案,需要具备以下先决条件:

  • 了解 JavaScript 的异步编程模型
  • 了解 ES6 Promise 对象
2个回答

9

简介

JavaScript 具有异步模型。每当完成异步操作后,您通常希望在此之后执行一些代码。最初,回调函数经常用于解决此问题。然而,当编写具有多个异步元素的编程代码时,使用回调函数会出现问题。因为当你在彼此嵌套的多个回调函数中时,代码很快变得难以维护。这种反面模式称为callback hell(回调地狱)。

承诺

Promise 解决了内部回调所出现的许多问题。Promise 链是 Promise 的一个关键特性。这使得语法比回调更加简洁,容易进行错误处理。以下是一个示例:

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。异步函数具有以下特点:

  • 在函数声明/表达式前加上 async 可以将该函数转换为异步函数。正如其名称所示,异步函数被异步执行。
  • 异步函数总是返回一个 Promise。它会用 Promise.resolve(returnval) 包装任何返回值。但是,当异步函数内发生未捕获的错误时,它会用 Promise.catch(returnval) 包装返回值。
  • 在异步函数内部,可以使用 await 关键字,在任何 Promise 前面使用 await 使 JS 代码停止执行,直到 Promise 被处理。也就是说,必须先实现或拒绝 Promise,然后才能执行异步函数内的任何进一步代码。
  • await 要么返回已实现 Promise 的值,要么在被拒绝的 Promise 的情况下引发错误。我们可以使用常规的 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");

什么时候使用异步函数

理论上,在使用 promise 时都可以使用异步函数。然而,当有多个返回 promise 的异步操作彼此依赖时,异步函数的强大优势才真正开始显示。

因为异步函数允许我们以同步方式编写基于 promise 的异步代码。代码仍然是异步的,但现在我们可以像读同步代码一样来阅读它。与 promise 链相比,这种编写方式更易于阅读和维护,从而能够更好地进行扩展(在我看来)。

以下是这种可读性的一个示例:

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

1
“await”关键字可以在任何表达式之前使用,不一定是一个promise。例如,语法正确的写法是“await 42”。这基本上是一个无操作,但它将触发等待机制并暂停函数执行。它相当于“await Promise.resolve(42)”。 - VLAZ
感谢您的添加! - Willem van der Veen

0

是的,这对我来说也有点不清楚。例如,这是来自https://javascript.info/callbacks的引用:

JavaScript主机环境提供了许多函数,允许您安排异步操作。换句话说,我们现在启动的操作,但它们稍后完成。

我的意思是,有没有我们现在启动并在之前完成的操作?在我看来,单独谈论异步操作是没有意义的。我们需要至少两行代码。

fst()
snd()

在同步代码中,snd 将在 fst 完成后开始执行,但在浏览器中,如果 fst 是一些需要时间的请求,它将阻塞 snd。这就是为什么在 JavaScript 中有回调函数,它们不会阻塞主程序的执行。也就是说,fst 不是在启动后立即完成,而是稍后完成,比 snd 更晚。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接