ES6 导入的定义执行顺序是什么?

What is the defined execution order of ES6 imports?

我尝试在互联网上搜索导入模块的执行顺序。例如,假设我有以下代码:

import "one"
import "two"
console.log("three");

其中one.jstwo.js定义如下:

// one.js
console.log("one");

// two.js
console.log("two");

控制台输出是否保证为:

one
two
three

还是未定义?

JavaScript 模块被评估异步。但是,所有导入都在模块主体进行导入之前进行评估。这使得 JavaScript 模块不同于 Axel Rauschmayer Exploring ES6CommonJS modules in Node or <script> tags without the async attribute. JavaScript modules are closer to the AMD spec when it comes to how they are loaded. For more detail, see section 16.6.1

因此,在提问者提供的例子中,无法保证执行顺序。有两种可能的结果。我们可能会在控制台中看到:

one
two
three

或者我们可能会看到这个:

two
one
three

换句话说,两个导入的模块可以以任何顺序执行它们的 console.log() 调用;它们相对于 彼此 是异步的。但它们肯定会在导入它们的模块主体之前执行,因此 "three" 保证最后记录。

使用 top-level await 语句(现在在 Chrome 中实现)时可以观察到模块的异步性。例如,假设我们稍微修改一下提问者的例子:

// 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

自 ES2020 更新

根据 ,从 ES2020 开始,非异步模块的评估顺序似乎得到保证。因此,如果您知道要导入的 none 个模块包含顶级 await 语句,它们将按照导入的顺序执行。在提问者的例子中,控制台输出总是:

one
two
three

根据最新规范InnerModuleEvaluation, the order of module.ExecuteModule() is guaranteed since [[RequestedModules]] is an ordered list of source code occurrences

// 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