Top-Level await
The abstract operation AsyncFunctionStart takes arguments promiseCapability and asyncFunctionBody. It performs the following steps when called:
HostImportModuleDynamically is a host-defined abstract operation that performs any necessary setup work in order to make available the module corresponding to the import()
The implementation of HostImportModuleDynamically must conform to the following requirements:
The actual process performed is host-defined, but typically consists of performing whatever I/O operations are necessary to allow
The abstract operation FinishDynamicImport takes arguments referencingScriptOrModule, specifier, promiseCapability (a PromiseCapability import()
A CallDynamicImportResolved function is an anonymous built-in function with no internal slots and has one argument result. When a CallDynamicImportResolved function is called it performs the following steps:
A CallDynamicImportRejected function is an anonymous built-in function with no internal slots and has one argument error. When a CallDynamicImportRejected function is called it performs the following steps:
Field Name | Value Type | Meaning |
---|---|---|
[[Realm]] |
|
The |
[[Environment]] |
module |
The |
[[Namespace]] |
Object | |
The Module Namespace Object ( |
[[HostDefined]] |
Any, default value is |
Field reserved for use by host environments that need to associate additional information with a module. |
Method | Purpose |
---|---|
GetExportedNames(exportStarSet) | Return a list of all names that are either directly or indirectly exported from this module. |
ResolveExport(exportName, resolveSet) |
Return the binding of a name exported by this module. Bindings are represented by a ResolvedBinding Record, of the form { [[Module]]: Each time this operation is called with a specific exportName, resolveSet pair as arguments it must return the same result if it completes normally. |
Link() |
Prepare the module for evaluation by transitively resolving all module dependencies and creating a module |
Evaluate() |
Returns a promise for the evaluation of this module and its dependencies, resolving on successful evaluation or if it has already been evaluated successfully, and rejecting for an evaluation error or Link must have completed successfully prior to invoking this method. |
A Cyclic Module Record is used to represent information about a module that can participate in dependency cycles with other modules that are subclasses of the
In addition to the fields defined in
Field Name | Value Type | Meaning |
---|---|---|
[[Status]] |
|
Initially |
[[EvaluationError]] |
An |
A completion of type |
[[DFSIndex]] |
|
Auxiliary field used during Link and Evaluate only.
If [[Status]] is |
[[DFSAncestorIndex]] |
|
Auxiliary field used during Link and Evaluate only.
If [[Status]] is |
[[RequestedModules]] |
|
A |
[[CycleRoot]] |
|
The first visited module of the cycle, the root DFS ancestor of the strongly connected component. For a module not in a cycle this would be the module itself. |
[[Async]] | Boolean |
Whether this module is individually asynchronous (for example, if it's a |
[[AsyncEvaluation]] | Boolean |
Whether this module is either itself async or has an asynchronous dependency.
Note: The order in which this field is set is used to order queued executions, see |
[[TopLevelCapability]] |
Promise Capability | |
If Evaluate() was called on this module, this field contains the Promise capability for that entire evaluation.
It is used to settle the Promise object that is returned from the Evaluate() abstract method.
This field will be |
[[AsyncParentModules]] |
|
If this module or a dependency has [[Async]] |
[[PendingAsyncDependencies]] |
|
This tracks the number of async dependency modules remaining to execute for this module if it has any asynchronous dependencies. A module with async dependencies will be executed when this field reaches 0 and there are no execution errors. |
In addition to the methods defined in
Method | Purpose |
---|---|
|
Initialize the |
|
Evaluate the module's code within its |
The Link concrete method of a
On success, Link transitions this module's [[Status]] from
This abstract method performs the following steps (most of the work is done by the auxiliary function
The abstract operation InnerModuleLinking takes arguments module (a
The Evaluate concrete method of a
Evaluate transitions this module's [[Status]] from
If execution results in an exception, that exception is recorded in the [[EvaluationError]] field and rethrown by future invocations of Evaluate.
The Promise returned by Evaluate is allocated by the first invocation of Evaluate, and its capability is stored in the [[TopLevelCapability]] field. If execution results in an exception, the Promise is rejected. Future invocations of Evaluate return the same Promise.
This abstract method performs the following steps (most of the work is done by the auxiliary function
The abstract operation InnerModuleEvaluation takes arguments module (a
A module is
Any modules depending on a module of an async cycle when that cycle is not
A CallAsyncModuleFulfilled function is an anonymous built-in function with a [[Module]] internal slot. When a CallAsyncModuleFulfilled function is called that expects no arguments it performs the following steps:
A CallAsyncModuleRejected function is an anonymous built-in function with a [[Module]] internal slot. When a CallAsyncModuleRejected function is called with argument error it performs the following steps:
When an async execution for a root module is fulfilled, this function determines the list of modules which are able to synchronously execute together on this completion, populating them in execList.
This non-normative section gives a series of examples of the linking and evaluation of a few common module graphs, with a specific focus on how errors can occur.
First consider the following simple module graph:
Let's first assume that there are no error conditions. When a host first calls A.Link(), this will complete successfully by assumption, and recursively link modules B and C as well, such that A.[[Status]] = B.[[Status]] = C.[[Status]] =
Consider then cases involving linking errors. If
Finally, consider a case involving evaluation errors. If
The difference here between linking and evaluation errors is due to how evaluation must be only performed once, as it can cause side effects; it is thus important to remember whether evaluation has already been performed, even if unsuccessfully. (In the error case, it makes sense to also remember the exception because otherwise subsequent Evaluate() calls would have to synthesize a new one.) Linking, on the other hand, is side-effect-free, and thus even if it fails, it can be retried at a later time with no issues.
Now consider a different type of error condition:
In this scenario, module A declares a dependency on some other module, but no
LastlyNow, consider a module graph with a cycle:
Here we assume that the entry point is module A, so that the host proceeds by calling A.Link(), which performs
An analogous story occurs for the evaluation phase of a cyclic module graph, in the success case.
Now consider a case where A has an linking error; for example, it tries to import a binding from C that does not exist. In that case, the above steps still occur, including the early return from the second call to
Finally, consider a case where A has an evaluation error; for example, its source code throws an exception. In that case, the evaluation-time analog of the above steps still occurs, including the early return from the second call to await
through the whole dependency graph through the
Lastly, consider a module graph with a cycle, where all modules complete asynchronously:
Linking happens as before, and all modules end up with [[Status]] set to
Calling A.Evaluate() triggers
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
A | 0 | 0 | « » | 2 (B and C) | ||
B | 1 | 0 | « A » | 1 (D) | ||
C | 2 | 0 | « A » | 2 (D and E) | ||
D | 3 | 0 | « B, C » | 0 | ||
E | 4 | 4 | « C » | 0 |
Let us assume that E finishes executing first.
When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
C | 2 | 0 | « A » | 1 (D) | ||
E | 4 | 4 | « C » | 0 |
D is next to finish (as it was the only module that was still executing).
When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
B | 1 | 0 | « A » | 0 | ||
C | 2 | 0 | « A » | 0 | ||
D | 3 | 0 | « B, C » | 0 |
Let us assume that C finishes executing next.
When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
A | 0 | 0 | « » | 1 (B) | ||
C | 2 | 0 | « A » | 0 |
Then, B finishes executing.
When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
A | 0 | 0 | « » | 0 | ||
B | 1 | 0 | « A » | 0 |
Finally, A finishes executing.
When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|---|---|
A | 0 | 0 | « » | 0 |
Alternatively, consider a failure case where C fails execution and returns an error before B has finished executing. When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[EvaluationError]] |
---|---|---|---|---|---|---|---|
A | 0 | 0 | « » | 1 (B) | |||
C | 2 | 1 | « A » | C's evaluation error |
A will be rejected with the same error as C since C will call
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[EvaluationError]] |
---|---|---|---|---|---|---|---|
A | 0 | 0 | « » | 0 | C's Evaluation Error |
Then, B finishes executing without an error. When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[EvaluationError]] |
---|---|---|---|---|---|---|---|
A | 0 | 0 | « » | 0 | C's Evaluation Error | ||
B | 1 | 0 | « A » | 0 |
The abstract operation ParseModule takes arguments sourceText (ECMAScript source text), realm, and hostDefined. It creates a
await
.An implementation may parse module source text and analyse it for Early Error conditions prior to the evaluation of ParseModule for that module source text. However, the reporting of any errors must be deferred until the point where this specification actually performs ParseModule upon that source text.
The ExecuteModule concrete method of a
This abstract method performs the following steps:
await
is parsed as an
When When await
is parsed as a await
may be parsed as an identifier when the [Await] parameter is absent. This includes the following contexts: