?
u
/
This specification defines several kinds of built-in
A export *
export items. Each String-valued own
An object is a module namespace exotic object if its [[GetPrototypeOf]], [[SetPrototypeOf]], [[IsExtensible]], [[PreventExtensions]], [[GetOwnProperty]], [[DefineOwnProperty]], [[HasProperty]], [[Get]], [[Set]], [[Delete]], and [[OwnPropertyKeys]] internal methods use the definitions in this section, and its other essential internal methods use the definitions found in
Internal Slot | Type | Description |
---|---|---|
[[Module]] |
a |
The |
[[Exports]] |
a |
A |
[[Deferred]] | a Boolean |
Whether this module namespace was obtained through import defer /import.defer() . Deferred namespaces can have side effects when accessing properties on them.
|
The [[Get]] internal method of a
import defer * as x from "..."; export { x }
, binding.[[BindingName]] is ResolveExport is side-effect free. Each time this operation is called with a specific exportName, resolveSet pair as arguments it must return the same result. An implementation might choose to pre-compute or cache the ResolveExport results for the [[Exports]] of each
The abstract operation EnsureDeferredNamespaceEvaluation takes argument O (a Module Namespace Exotic Object) and returns either a
The abstract operation ReadyForSyncExecution takes argument module (a
The abstract operation ModuleNamespaceCreate takes arguments module (a
The abstract operation EvaluateImportCall takes arguments specifierExpression (a ParseNode) and phase (
import
(
)
.
It performs the following steps when called:
A DynamicImportState Record is a
Field Name | Value Type | Meaning |
---|---|---|
[[PromiseCapability]] |
a |
The promise to resolve when the loading process finishes. |
[[Phase]] |
|
The target import phase |
The abstract operation ContinueDynamicImport takes arguments promiseCapability (a , payload (a import()
A ModuleRequest Record represents the request to import a module up to a given phase. It consists of the following fields:
Field Name | Value Type | Meaning |
---|---|---|
[[Specifier]] | String | The module specifier |
[[Phase]] |
|
The target import phase |
The Strings
A Module Record encapsulates structural information about the imports and exports of a single module. This information is used to link the imports and exports of sets of connected modules. A Module Record includes four fields that are only used when evaluating a module.
For specification purposes Module Record values are values of the
Module Record defines the fields listed in
Field Name | Value Type | Meaning |
---|---|---|
[[Realm]] |
a |
The |
[[Environment]] |
a |
The |
[[Namespace]] |
an Object or |
The Module Namespace Object ( |
[[DeferredNamespace]] |
an Object or |
The Module Namespace Object ( |
[[HostDefined]] |
anything (default value is |
Field reserved for use by |
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]] |
a |
A |
[[DFSIndex]] |
an |
Auxiliary field used during Link and Evaluate only. If [[Status]] is either |
[[DFSAncestorIndex]] |
an |
Auxiliary field used during Link and Evaluate only. If [[Status]] is either |
[[RequestedModules]] |
a |
A |
[[LoadedModules]] |
a |
A map from the specifier strings used by the module represented by this record to request the importation of a module to the resolved |
[[CycleRoot]] |
a |
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. Once Evaluate has completed, a module's [[DFSAncestorIndex]] is the [[DFSIndex]] of its [[CycleRoot]]. |
[[HasTLA]] | a Boolean |
Whether this module is individually asynchronous (for example, if it's a |
[[AsyncEvaluation]] | a Boolean |
Whether this module is either itself asynchronous or has an asynchronous dependency. Note: The order in which this field is set is used to order queued executions, see |
[[TopLevelCapability]] |
a |
If this module is the [[CycleRoot]] of some cycle, and Evaluate() was called on some module in that cycle, this field contains the |
[[AsyncParentModules]] |
a |
If this module or a dependency has [[HasTLA]] |
[[PendingAsyncDependencies]] |
an |
If this module has any asynchronous dependencies, this tracks the number of asynchronous dependency modules remaining to execute for this module. A module with asynchronous dependencies will be executed when this field reaches 0 and there are no execution errors. |
In addition to the methods defined in
Method | Purpose |
---|---|
InitializeEnvironment() |
Initialize the |
ExecuteModule( [ promiseCapability ] ) |
Evaluate the module's code within its |
A GraphLoadingState Record is a
Field Name | Value Type | Meaning |
---|---|---|
[[PromiseCapability]] |
a |
The promise to resolve when the loading process finishes. |
[[IsLoading]] | a Boolean | It is true if the loading process has not finished yet, neither successfully nor with an error. |
[[PendingModulesCount]] |
a non-negative |
It tracks the number of pending |
[[Visited]] |
a |
It is a list of the |
[[HostDefined]] |
anything (default value is |
It contains |
The LoadRequestedModules concrete method of a
<link rel="preload" as="...">
tags.
import()
expressions never set the hostDefined parameter.
The abstract operation InnerModuleLoading takes arguments state (a
The abstract operation ContinueModuleLoading takes arguments state (a
The Link concrete method of a
The abstract operation InnerModuleLinking takes arguments module (a
The Evaluate concrete method of a
The abstract operation InnerModuleEvaluation takes arguments module (a
A module is
Any modules depending on a module of an asynchronous cycle when that cycle is not
The abstract operation EvaluateSync takes argument module (a
The abstract operation GatherAsynchronousTransitiveDependencies takes argument module (a
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
Consider then cases involving linking errors, after a successful call to A.LoadRequestedModules(). If
Finally, consider a case involving evaluation errors after a successful call to Link(). If
Now consider a different type of error condition:
In this scenario, module A declares a dependency on some other module, but no
The difference here between loading, linking and evaluation errors is due to the following characteristic:
Now, consider a module graph with a cycle:
Here we assume that the entry point is module A, so that the
Then the
An analogous story occurs for the evaluation phase of a cyclic module graph, in the success case.
Now consider a case where A has a 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
Alternatively, 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:
Loading and linking happen as before, and all modules end up with [[Status]] set to
Calling A.Evaluate() calls
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, await
). The fields of the updated modules are as given in
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 » | 0 | 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 |
Then, B finishes executing without an error. When that happens,
Module | [[DFSIndex]] | [[DFSAncestorIndex]] | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[EvaluationError]] |
---|---|---|---|---|---|---|---|
A | 0 | 0 | « » | 0 | C's |
||
B | 1 | 0 | « A » | 0 |
Deferred imports complicate handling of module graphs, because they allow deferring evaluation of part of the graph while still eagerly evaluating the asynchronous subgraphs of a deferred portion. In this section, deferred imports are marked with dashed arrows and modules using top-level await are marked with TLA.
Consider the following graph, assuming that all the modules have already their [[Status]] set to
Calling A.Evaluate() calls
Consider the same graph, but with C using top-level await:
Calling A.Evaluate() calls
Module | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|
A | « » | 1 (C) | ||
B | « » | 0 | ||
C | « A » | 0 | ||
D | « » | 0 |
Let us assume that C succesfully finishes evaluating. When that happens,
Module | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] |
---|---|---|---|---|
A | « » | 0 | ||
B | « » | 0 | ||
C | « A » | 0 | ||
D | « » | 0 |
If later B.Evaluate() is called, then the
Alternatively, consider a failure case where C fails to execute with an exception error. When that happens,
Module | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[EvaluationError]] |
---|---|---|---|---|---|
A | « » | 1 (C) | error | ||
B | « » | 0 | |||
C | « B » | 0 | error | ||
D | « » | 0 |
If at any later point in time B.Evaluate() is called, it will perform
Consider now a graph with a deferred import taking part in a dependencies cycle, and assume that the evaluation of A calls B.Evaluate():
As in the previous example, calling A.Evaluate() calls
Module | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[CycleRoot]] |
---|---|---|---|---|---|
A | « » | 1 (C) | A | ||
B | « » | 0 | |||
C | « A » | 0 | A |
Assume now that C succesfully finishes evaluating. When that happens
Module | [[Status]] | [[AsyncEvaluation]] | [[AsyncParentModules]] | [[PendingAsyncDependencies]] | [[CycleRoot]] |
---|---|---|---|---|---|
A | « » | 0 | A | ||
B | « » | 0 | B | ||
C | « A » | 0 | A |
Once the call to A.ExecuteModule() completes, A.[[Status]] transitions to
The InitializeEnvironment concrete method of a
export * as ns from "";
declaration. import * as ns from ""; export { ns }
indirect re-exports have resolution.[[BindingName]] set to The abstract operation GetModuleNamespace takes arguments module (an instance of a concrete subclass of
GetModuleNamespace never throws. Instead, unresolvable names are simply excluded from the namespace at this point. They will lead to a real linking error later unless they are all ambiguous star exports that are not explicitly requested anywhere.
The
The above rule means that each
The
ExportedNames are the externally visible names that a
It is defined piecewise over the following productions:
The
© 2024 Nicolò Ribaudo
All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT https://ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.