ES2017 新特性:Async Functions (异步函数)
概述
async(异步) 函数变体
以下是已经存在的异步函数变体。请注意无处不在的 async
关键字。
- 异步函数声明:
async function foo() {}
- 异步函数表达式:
const foo = async function () {};
- 异步函数定义:
let obj = { async foo() {} }
- 异步箭头函数:
const foo = async () => {};
async(异步) 函数总是返回 Promises
async(异步) 函数的 Promise 完成状态:
async(异步) 函数的 Promise 拒绝状态:
通过 await
处理 async(异步) 计算的结果和错误
await
(只允许在 async(异步) 函数内部使用)等待其操作对象 Promise 返回:
- 如果 Promise 是完成状态,
await
的结果是完成态的值。 - 如果 Promise 是拒绝状态,
await
会抛出拒绝值。
处理单个 async(异步) 返回值:
按顺序处理多个 async(异步) 返回值:
并行处理多个 async(异步) 返回值:
错误处理:
理解 async(异步) 函数
在我解释 async(异步) 函数之前,我需要解释一下如何组合使用 Promises 和 Generator ,通过看起来同步的代码来执行 async(异步) 操作。
对于能够 async(异步) 计算其一次性结果的函数,作为 ES6 一部分的 Promises 已经变得流行起来。一个例子是 客户端 fetch API ,它是 XMLHttpRequest 获取数据的替代方法。使用示例如下:
通过 generator 来编写异步代码
co 是一个使用 Promise 和 generator 来实现看似同步编码的库,但与上一示例中使用的样式相同:
每次回调函数( generator 函数)产生一个 Promise 对象给 co ,回调会被暂停,只有当 Promise 执行完成后,co 才会继续执行回调 。 如果 Promise 处于完成状态,yield
返回完成状态的值,如果处于拒绝状态,yield
抛出拒绝状态的错误。此外,co 保证结果是通过回调执行完成才返回的(类似于 then()
所做的工作)。
通过 async(异步) 函数来编写异步代码
async(异步) 函数用的特定语法基本上和 co 类似:
在内部,异步函数写法更类似于 generators 。
以同步开始,异步处理的 async(异步) 函数
以下是 async(异步)函数是如何工作的:
- async(异步) 函数总是返回一个 Promise 对象
p
。Promise 对象在 async(异步) 函数开始执行时被创建。 - 函数体执行过程中,可以通过
return
或throw
终止执行。或者通过await
暂停执行,在这种情况下,通常会在以后继续执行。 - 返回 Promise 对象
p
。
当执行 async(异步) 函数的函数体时,return x
中的 x
是 Promise 对象 p
的完成状态的结果,而throw err
是 p
的拒绝状态的结果。执行结果是异步返回的。换句话说:then()
和 catch()
的回调总是在当前代码完成后执行。
以下是代码示例:
您可以认为是以下的执行顺序:
- 行A:async(异步) 函数以同步开始。async(异步) 函数的 Promise 通过
return
来返回完成状态的结果。 - 行C:执行继续。
- 行B:Promise 完成状态通知是异步发生的。
返回不被包裹的 Promise 对象
Promise 的 resolve 是一项标准操作。 return
就是使用它来 resolve async(异步) 函数的 Promise p
的。这意味着:
- 返回一个非 Promise 值,该值将被处理成
p
的完成状态值。 - 返回一个 Promise 对象,那么
p
此时相当于是该 Promise 的状态。
因此,您可以返回一个 Promise ,并且这个 Promise 不会包裹在别的 Promise 中:
有趣的是,返回一个拒绝状态(reject)的 Promise 对象会导致 async(异步) 函数被拒绝(reject)(通常,您可以使用 throw
):