转载:await - JavaScript | MDN
The await
operator is used to wait for a Promise
and get its fulfillment value. It can only be used inside an async function or a JavaScript module.
# Syntax
1 | await expression; |
# Parameters
-
expression
A
Promise
or any value to wait for.
# Return value
The fulfillment value of the promise, or the expression itself’s value itself if it’s not a Promise
.
# Exceptions
Throws the rejection reason if the promise is rejected.
# Description
The await
expression causes async function execution to pause until a promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment. When resumed, the value of the await
expression is that of the fulfilled promise.
The expression
is resolved in the same way as Promise.resolve()
, which means thenable objects are supported, and if expression
is not a promise, it’s implicitly wrapped in a Promise
and then resolved.
If the promise is rejected, the await
expression throws the rejected value. The function containing the await
expression will appear in the stack trace of the error. Otherwise, if the rejected promise is not awaited or is immediately returned, the caller function will not appear in the stack trace.
An await
splits execution flow, allowing the caller of the async function to resume execution. After the await
defers the continuation of the async function, execution of subsequent statements ensues. If this await
is the last expression executed by its function, execution continues by returning to the function’s caller a pending Promise
for completion of the await
's function and resuming execution of that caller.
Because await
is only valid inside async functions and modules, which themselves are asynchronous and return promises, the await
expression never blocks the main thread and only defers execution of code that actually depends on the result, i.e. anything after the await
expression.
# Examples
# Awaiting a promise to be fulfilled
If a Promise
is passed to an await
expression, it waits for the Promise
to be fulfilled and returns the fulfilled value.
1 | function resolveAfter2Seconds(x) { |
# Thenable objects
Thenable objects will be fulfilled just the same.
1 | async function f2() { |
# Conversion to promise
If the value is not a Promise
, it converts the value to a resolved Promise
, and waits for it.
1 | async function f3() { |
# Promise rejection
If the Promise
is rejected, the rejected value is thrown.
1 | async function f4() { |
# Handling rejected promises
You can handle rejected promises without a try
block by chaining a catch()
handler before awaiting the promise.
1 | const response = await promisedFunction().catch((err) => { |
# Top level await
You can use the await
keyword on its own (outside of an async function) within a JavaScript module. This means modules, with child modules that use await
, wait for the child module to execute before they themselves run, all while not blocking other child modules from loading.
Here is an example of a simple module using the Fetch API and specifying await within the export
statement. Any modules that include this will wait for the fetch to resolve before running any code.
1 | // fetch request |
# Control flow effects of await
When an await
is encountered in code (either in an async function or in a module), execution of all code following this is immediately paused and pushed into the microtask queue. The main thread is then freed for the next task in the event loop. This happens even if the awaited value is an already-resolved promise or not a promise. For example, consider the following code:
1 | async function foo(name) { |
In this case, the two async functions are synchronous in effect, because they don’t contain any await
expression. The three statements happen in the same tick. In promise terms, the function corresponds to:
1 | function foo(name) { |
However, as soon as there’s one await
, the function becomes asynchronous, and execution of following statements is deferred to the next tick.
1 | async function foo(name) { |
This corresponds to:
1 | function foo(name) { |
While the extra then()
handler is not necessary and can be merged with the previous one, its existence means the code will take one extra tick to complete. The same happens for await
. Therefore, make sure to use await
only when necessary (to unwrap promises into their values).
# Improving stack trace
Sometimes, the await
is omitted when a promise is directly returned from an async function.
1 | async function noAwait() { |
However, consider the case where someAsyncTask
asynchronously throws an error.
1 | async function lastAsyncTask() { |
Only lastAsyncTask
appears in the stack trace, because the promise is rejected after it has already been returned from noAwait
— in some sense, the promise is unrelated to noAwait
. To improve the stack trace, you can use await
to unwrap the promise, so that the exception gets thrown into the current function. The exception will then be immediately wrapped into a new rejected promise, but during error creation, the caller will appear in the stack trace.
1 | async function lastAsyncTask() { |
However, there’s a little performance penalty coming with return await
because the promise has to be unwrapped and wrapped again.
# Comments
1 | const getLastPost = async () => { |
-
promise.then
1
2
3
4
5const lastPost = getLastPost().then((post) => console.log(post));
console.log("end");
// end
// {title: 'at nam consequatur ea labore ea harum'} -
async wrap IIFE(Immediately Invoked Function Expression)
1
2
3
4
5
6
7
8(async () => {
const lastPost = await getLastPost();
console.log(lastPost);
})();
console.log("end");
// end
// {title: 'at nam consequatur ea labore ea harum'} -
top level await
1
2
3
4
5
6const lastPost = await getLastPost();
console.log(lastPost);
console.log("end");
// {title: 'at nam consequatur ea labore ea harum'}
// endImport in HTML need by module way.
1
<script type="module" defer src="script.js"></script>