ES6 模块导入是否挂起?

Are ES6 module imports hoisted?

我知道在新的 ES6 模块语法中,JavaScript 引擎将不必 评估 代码来了解所有 imports/exports,它只会解析它并“知道”加载什么。

这听起来像是吊装。 ES6模块是否吊装?如果是这样,它们会在 运行 代码之前加载吗?

这个代码可以吗?

import myFunc1 from 'externalModule1';

myFunc2();

if (Math.random()>0.5) {
    import myFunc2 from 'externalModule2';
}

ES6 规范可能会发生变化,但 this draft 是明确的:

The static variable resolution and linking pass checks for conflicts in imported variable names. If there is a conflict between two imported names, or an imported name and another local binding, then it is a compile-time error.

并且尝试在运行时导入是值得怀疑的想法,不仅在 ES6 中。同样来自草稿:

Compilation resolves and validates all variable definitions and references. Linking also happens at compile-time; linking resolves and validates all module imports and exports.

你可以看到Babel's ES6 implementation对此不太满意。

这将是一个语法错误。根据 this part of specification:

Module :
   ModuleBody

ModuleBody :
    ModuleItemList

ModuleItemList :
    ModuleItem
    ModuleItemList ModuleItem

ModuleItem :
    ImportDeclaration
    ExportDeclaration
    StatementListItem

表示模块只能包含ImportDeclarationExportDeclarationStatementListItem。 根据thisStatementListItem可以 不包含 ImportDeclarationExportDeclaration

import myFunc1 from 'externalModule1'; 

是进口申报,而:

if (Math.random()>0.5) {
    import myFunc2 from 'externalModule2';
}

是一个声明。所以你的代码会导致语法错误。

那"will they all be loaded before running the code?"呢。 This part of specification 包含下一句:

NOTE: Before instantiating a module, all of the modules it requested must be available.

所以,是的。 它们都会在运行代码之前加载。

经过更多研究,我发现:

  • 导入已暂停!根据ModuleDeclarationInstantiation
  • spec
  • 所有依赖模块将在 运行 任何代码之前加载。

此代码不会有任何错误,并且可以运行:

localFunc();

import {myFunc1} from 'mymodule';

function localFunc() { // localFunc is hoisted
    myFunc1();
}