async function
用来定义一个返回 Promise
返回其结果。如果你在代码中使用了异步函数,就会发现它的语法和结构会更像是标准的同步函数。
你还可以使用 异步函数表达式 来定义异步函数。
该交互式demo源文件存储于Github仓库中。如果希望为此交互式项目做出贡献,请 clone https://github.com/mdn/interactive-examples 项目并用pull形式向我们的原始仓库发出请求。
语法
async function name([param[, param[, ... param]]]) { statements }
参数
-
name
- 函数名称。
-
param
- 要传递给函数的参数。
-
statements
- 函数体语句。
-
返回值
-
返回的
Promise
对象会运行执行(resolve)异步函数的返回结果,或者运行拒绝(reject)——如果异步函数抛出异常的话。
描述
异步函数可以包含await
指令,该指令会暂停异步函数的执行,并等待Promise执行,然后继续执行异步函数,并返回结果。
记住,await 关键字只在异步函数内有效。如果你在异步函数外使用它,会抛出语法错误。
注意,当异步函数暂停时,它调用的函数会继续执行(收到异步函数返回的隐式Promise)
async
/await
的目的是简化使用多个 promise 时的同步行为,并对一组 Promises
执行某些操作。正如Promises
类似于结构化回调,async
/await
更像结合了generators和 promises。
示例
简单例子
var resolveAfter2Seconds = function() { console.log("starting slow promise"); return new Promise(resolve => { setTimeout(function() { resolve("slow"); console.log("slow promise is done"); }, 2000); }); }; var resolveAfter1Second = function() { console.log("starting fast promise"); return new Promise(resolve => { setTimeout(function() { resolve("fast"); console.log("fast promise is done"); }, 1000); }); }; var sequentialStart = async function() { console.log('==SEQUENTIAL START=='); // 1. Execution gets here almost instantly const slow = await resolveAfter2Seconds(); console.log(slow); // 2. this runs 2 seconds after 1. const fast = await resolveAfter1Second(); console.log(fast); // 3. this runs 3 seconds after 1. } var concurrentStart = async function() { console.log('==CONCURRENT START with await=='); const slow = resolveAfter2Seconds(); // starts timer immediately const fast = resolveAfter1Second(); // starts timer immediately // 1. Execution gets here almost instantly console.log(await slow); // 2. this runs 2 seconds after 1. console.log(await fast); // 3. this runs 2 seconds after 1., immediately after 2., since fast is already resolved } var concurrentPromise = function() { console.log('==CONCURRENT START with Promise.all=='); return Promise.all([resolveAfter2Seconds(), resolveAfter1Second()]).then((messages) => { console.log(messages[0]); // slow console.log(messages[1]); // fast }); } var parallel = async function() { console.log('==PARALLEL with await Promise.all=='); // Start 2 "jobs" in parallel and wait for both of them to complete await Promise.all([ (async()=>console.log(await resolveAfter2Seconds()))(), (async()=>console.log(await resolveAfter1Second()))() ]); } // This function does not handle errors. See warning below! var parallelPromise = function() { console.log('==PARALLEL with Promise.then=='); resolveAfter2Seconds().then((message)=>console.log(message)); resolveAfter1Second().then((message)=>console.log(message)); } sequentialStart(); // after 2 seconds, logs "slow", then after 1 more second, "fast" // wait above to finish setTimeout(concurrentStart, 4000); // after 2 seconds, logs "slow" and then "fast" // wait again setTimeout(concurrentPromise, 7000); // same as concurrentStart // wait again setTimeout(parallel, 10000); // truly parallel: after 1 second, logs "fast", then after 1 more second, "slow" // wait again setTimeout(parallelPromise, 13000); // same as parallel
await
and parallelism(并行)
在sequentialStart
中,程序在第一个await
停留了2秒,然后又在第二个await
停留了1秒。直到第一个计时器结束后,第二个计时器才被创建。程序需要3秒执行完毕。
在 concurrentStart
中,两个计时器被同时创建,然后执行await
。这两个计时器同时运行,这意味着程序完成运行只需要2秒,而不是3秒,即最慢的计时器的时间。
但是 await
仍旧是顺序执行的,第二个 await
还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。
如果你希望并行执行两个或更多的任务,你必须像在parallel
中一样使用await Promise.all([job1(), job2()])
。
async
/await和
Promise#then对比以及错误处理
大多数异步函数也可以使用Promises编写。但是,在错误处理方面,async
函数更容易捕获异常错误
上面例子中的concurrentStart
函数和concurrentPromise
函数在功能上都是等效的。在concurrentStart
函数中,如果任一await
ed调用失败,它将自动捕获异常,异步函数执行中断,并通过隐式返回Promise将错误传递给调用者。
在Promise例子中这种情况同样会发生,该函数必须负责返回一个捕获函数完成的Promise
。在concurrentPromise
函数中,这意味着它从Promise.all([]).then()
返回一个Promise。事实上,在此示例的先前版本忘记了这样做!
但是,async
函数仍有可能然可能错误地忽略错误。
以parallel
异步函数为例。 如果它没有等待await
(或返回)Promise.all([])
调用的结果,则不会传播任何错误。
虽然parallelPromise
函数示例看起来很简单,但它根本不会处理错误! 这样做需要一个类似于return
Promise.all([])
处理方式。
使用async
函数重写 promise 链
返回 Promise
的 API 将会产生一个 promise 链,它将函数肢解成许多部分。例如下面的代码:
function getProcessedData(url) { return downloadData(url) // 返回一个 promise 对象 .catch(e => { return downloadFallbackData(url) // 返回一个 promise 对象 }) .then(v => { return processDataInWorker(v); // 返回一个 promise 对象 }); }
可以重写为单个async
函数:
async function getProcessedData(url) { let v; try { v = await downloadData(url); } catch (e) { v = await downloadFallbackData(url); } return processDataInWorker(v); }
注意,在上述示例中,return
语句中没有 await
操作符,因为 async function
的返回值将被隐式地传递给
。Promise.resolve
return await promiseValue;
与 return promiseValue;的比较
返回值隐式的传递给
Promise.resolve
,并不意味着return await promiseValue;和return promiseValue;
在功能上相同。
看下下面重写的上面代码,在processDataInWorker
抛出异常时返回了null:
async function getProcessedData(url) {
let v;
try {
v = await downloadData(url);
} catch(e) {
v = await downloadFallbackData(url);
}
try {
return await processDataInWorker(v); // 注意 `return await` 和单独 `return` 的比较
} catch (e) {
return null;
}
}
简单地写上return processDataInworker(v);将导致在processDataInWorker(v)
出错时function返回值为Promise
,return await foo;
将等待foo
执行(resolve)或拒绝(reject),如果是拒绝,将会在返回前抛出异常。
规范
Specification | Status | Comment |
---|---|---|
ECMAScript Latest Draft (ECMA-262) async function |
Draft | 初始定义于ES2017. |
ECMAScript 2017 (ECMA-262) async function |
Standard |
浏览器兼容性
Desktop | Mobile | Server | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
async function |
Chrome Full support 55 | Edge Full support 15 | Firefox Full support 52 | IE No support No | Opera Full support 42 | Safari Full support 10.1 | WebView Android Full support Yes | Chrome Android Full support 55 | Firefox Android Full support 52 | Opera Android Full support 42 | Safari iOS Full support 10.3 | Samsung Internet Android Full support 6.0 | nodejs Full support 7.6.0
|
Legend
- Full support
- Full support
- No support
- No support
- User must explicitly enable this feature.
- User must explicitly enable this feature.