我试过在互联网上搜索导入module的执行顺序。例如,假设我有以下代码:
import "one"
import "two"
console.log("three");
其中one.js
和two.js
定义如下:
// one.js
console.log("one");
// two.js
console.log("two");
控制台输出是否保证为:
one
two
three
或者它是未定义的?
我试过在互联网上搜索导入module的执行顺序。例如,假设我有以下代码:
import "one"
import "two"
console.log("three");
其中one.js
和two.js
定义如下:
// one.js
console.log("one");
// two.js
console.log("two");
控制台输出是否保证为:
one
two
three
或者它是未定义的?
JavaScript module是异步评估的。但是,所有导入都会在module主体进行导入之前进行评估。这使得 JavaScript module不同于Node 中的 CommonJS module或没有该属性的<script>
标签async
。JavaScript module在加载方式方面更接近于AMD 规范。有关更多详细信息,请参阅Axel Rauschmayer的Exploring ES6的第 16.6.1 节。
因此,在提问者提供的例子中,无法保证执行的顺序。有两种可能的结果。我们可能会在控制台中看到:
one
two
three
或者我们可能会看到这个:
two
one
three
换句话说,两个导入的module可以console.log()
以任意顺序执行它们的调用;它们是异步相对于彼此。但是它们肯定会在导入它们的module主体之前执行,因此"three"
保证最后记录。
使用顶级await
语句(现在在 Chrome 中实现)时可以观察到module的异步性。例如,假设我们稍微修改提问者的例子:
// main.js
import './one.js';
import './two.js';
console.log('three');
// one.js
await new Promise(resolve => setTimeout(resolve, 1000));
console.log('one');
// two.js
console.log('two');
当我们运行时main.js
,我们会在控制台中看到以下内容(添加了时间戳以进行说明):
[0s] two
[1s] one
[1s] three
根据petamoriken 的回答,从ES2020 开始,非异步module的评估顺序似乎得到了保证。因此,如果您知道要导入的module中没有一个包含顶级await
语句,它们将按照导入的顺序执行。在提问者的例子中,控制台输出将始终是:
one
two
three
根据最新的规范InnerModuleEvaluation, 的顺序是module.ExecuteModule()
有保证的,因为[[RequestedModule]] 是源代码出现的有序列表。
// 16.2.1.5.2.1 rough sketch
function InnerModuleEvaluation(module, stack, index) {
// ...
// 8
module.[[PendingAsyncDependencies]] = 0;
// ...
// 11: resolve dependencies (source code occurrences order)
for (required of module.[[RequestedModules]]) {
let requiredModule = HostResolveImportedModule(module, required);
// **recursive**
InnerModuleEvaluation(requiredModule, stack, index);
// ...
if (requiredModule.[[AsyncEvaluation]]) {
++module.[[PendingAsyncDependencies]];
}
}
// 12: execute
if (module.[[PendingAsyncDependencies]] > 0 || module.[[HasTLA]]) {
module.[[AsyncEvaluation]] = true;
if (module.[[PendingAsyncDependencies]] === 0) {
ExecuteAsyncModule(module);
}
} else {
module.ExecuteModule();
}
// ...
}
控制台输出始终如下:
one
two
three