js-async异步函数

高手们在线问下,js-async异步函数
最新回答
锁住浪漫

2026-10-21 13:56:10

async函数是使用async关键字声明的函数,它是AsyncFunction构造函数的实例,并允许使用await关键字。这使得写出基于Promise的异步行为变得更加简洁,无需刻意地链式调用promise。

async函数可以作为表达式来定义。

语法包含函数名称、参数名称、函数主体的表达式和返回值。返回值是一个Promise,该Promise在async函数执行后,通过一个由async函数返回的值被解决,或通过一个从async函数中抛出的(或其中没有被捕获到的)异常被拒绝。

async函数可能包含0个或多个await表达式。await表达式会暂停async函数的执行进程并出让其控制权,直到其等待的基于Promise的异步操作被兑现或被拒绝。此时,promise的解决值将作为await表达式的返回值。使用async/await关键字可以在异步代码中使用普通的try / catch代码块。

await关键字仅在async函数内有效。在async函数体之外使用它会导致语法错误。

async/await的目的在于简化使用基于Promise的API时所需的语法,其行为类似于搭配使用生成器和Promise。

async函数一定会返回一个Promise对象。如果async函数的返回值看起来不是Promise,那么它将会被隐式地包装在一个Promise中。

例如,在代码中,等价于

async函数的函数体可以被看作是由0个或多个await表达式分割开来的。从第一行代码直到(并包括)第一个await表达式(如果有的话)都是同步运行的。因此,一个不含await表达式的async函数是同步运行的。然而,如果函数体内有一个await表达式,async函数就一定会异步执行。

例如:

等价于

在await表达式之后的代码可以被认为是存在在链式调用的then回调中,多个await表达式都将加入链式调用的then回调中,返回值将作为最后一个then回调的返回值。

在接下来的例子中,我们将使用await执行两次Promise,整个foo函数的执行将会被分为三个阶段。

foo函数的第一行将会同步执行,await将会等待Promise的结束。然后暂停通过foo的进程,并将控制权交还给调用foo的函数。

一段时间后,当第一个Promise完结的时候,控制权将重新回到foo函数内。示例中将会将1(Promise状态为fulfilled)作为结果返回给await表达式的左边即result1。接下来函数会继续进行,到达第二个await区域,此时foo函数的进程将再次被暂停。

一段时间后,同样当第二个Promise完结的时候,result2将被赋值为2,之后函数将会正常同步执行,将默认返回undefined。

注意:Promise链不是一次就构建好的,相反,Promise链是分阶段构造的,因此在处理异步函数时必须注意对错误函数的处理。

例如,在下面的代码中,在Promise链上配置了.catch处理程序,将抛出未处理的Promise错误。这是因为p2返回的结果不会被await处理。

简单例子

在sequentialStart中,程序在第一个await停留了2秒,然后又在第二个await停留了1秒。直到第一个计时器结束后,第二个计时器才被创建。程序需要3秒执行完毕。

在 concurrentStart中,两个计时器被同时创建,然后执行await。这两个计时器同时运行,这意味着程序完成运行只需要2秒,而不是3秒,即最慢的计时器的时间。

但是 await 仍旧是顺序执行的,第二个 await 还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。

如果你希望并行执行两个或更多的任务,你必须像在parallel中一样使用await Promise.all([job1(), job2()])。

async/await和Promise#then对比以及错误处理

大多数async函数也可以使用Promises编写。但是,在错误处理方面,async函数更容易捕获异常错误。

上面例子中的concurrentStart函数和concurrentPromise函数在功能上都是等效的。在concurrentStart函数中,如果任一awaited调用失败,它将自动捕获异常,async函数执行中断,并通过隐式返回Promise将错误传递给调用者。

在Promise例子中这种情况同样会发生,该函数必须负责返回一个捕获函数完成的Promise。在concurrentPromise函数中,这意味着它从Promise.all([]).then()返回一个Promise。事实上,在此示例的先前版本忘记了这样做!

但是,async函数仍有可能然可能错误地忽略错误。

以parallel async函数为例。 如果它没有等待await(或返回)Promise.all([])调用的结果,则不会传播任何错误。

虽然parallelPromise函数示例看起来很简单,但它根本不会处理错误! 这样做需要一个类似于return Promise.all([])处理方式。

使用async函数重写 promise 链

返回 Promise的 API 将会产生一个 promise 链,它将函数肢解成许多部分。例如下面的代码:

可以重写为单个async函数:

注意,在上述示例中,return 语句中没有 await 操作符,因为 async function 的返回值将被隐式地传递给 Promise.resolve。

return await promiseValue; 与 return promiseValue;的比较

返回值隐式的传递给Promise.resolve,并不意味着return await promiseValue;和return promiseValue;在功能上相同。

看下下面重写的上面代码,在processDataInWorker抛出异常时返回了null:

简单地写上return processDataInworker(v);将导致在processDataInWorker(v)出错时function返回值为Promise而不是返回null。return foo;和return await foo;,有一些细微的差异:return foo;不管foo是promise还是rejects都将会直接返回foo。相反地,如果foo是一个Promise,return await foo;将等待foo执行(resolve)或拒绝(reject),如果是拒绝,将会在返回前抛出异常。