async function
声明用于定义一个返回 AsyncFunction
对象的异步函数。异步函数是指通过事件循环异步执行的函数,它会通过一个隐式的 Promise
返回其结果。但是如果你的代码使用了异步函数,它的语法和结构会更像是标准的同步函数。
你还可以使用 异步函数表达式 来定义异步函数。
该交互式demo源文件存储于Github仓库中。如果希望为此交互式项目做出贡献,请 clone https://github.com/mdn/interactive-examples 项目并用pull形式向我们的原始仓库发出请求。
async function name([param[, param[, ... param]]]) { statements }
name
param
statements
Promise
对象会以async function的返回值进行解析(resolved),或者以该函数抛出的异常进行回绝(rejected)。当调用一个 async
函数时,会返回一个 Promise
对象。当这个 async
函数返回一个值时,Promise
的 resolve 方法会负责传递这个值;当 async
函数抛出异常时,Promise
的 reject 方法也会传递这个异常值。
async
函数中可能会有 await
表达式,这会使 async
函数暂停执行,等待 Promise
的结果出来,然后恢复async
函数的执行并返回解析值(resolved)。
注意, await
关键字仅仅在 async
function中有效。如果在 async function
函数体外使用 await
,你只会得到一个语法错误(SyntaxError
)。
async
/await
的目的是简化使用多个 promise 时的同步行为,并对一组 Promises
执行某些操作。正如Promises
类似于结构化回调,async
/await
类似于组合生成器和 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
还是得等待第一个执行完。在这个例子中,这使得先运行结束的输出出现在最慢的输出之后。
如果你希望并行等待
两个或者是更多的任务,你必须使用await Promise.all([job1(), job2()])
,正如parallel
例子。
async
/await
vs Promise#then and error handlingMost async functions can also be written as regular functions using Promises. However async
functions are a little bit less error-prone when it comes to error handling.
Both concurrentStart
and concurrentPromise
are functionally equivalent.
In concurrentStart
, if either of the await
ed calls fail, the exception will be automatically caught, the async function execution interrupted, and the Error propagated to the caller through the implicit return Promise.
For the same to happen in the Promise case, the function must take care of returning a Promise
which captures the completion of the function. In concurrentPromise
that means return
ing the promise from Promise.all([]).then()
. As a matter of fact, a previous version of this example forgot to do this!
It is however still possible for async
functions to mistakenly swallow errors.
Take for example the parallel
async function. If it didn't await
(or return
) the result of the Promise.all([])
call, any Error would not have been propagated.
While the parallelPromise
example seem simple, it does not handle errors at all! Doing so would require a similar 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
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 Yes | 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 | Edge Mobile Full support Yes | Firefox Android Full support 52 | Opera Android Full support 42 | Safari iOS Full support 10.1 | Samsung Internet Android Full support 6.0 | nodejs
Full support
7.6.0
|