ES6中的静态导入是什么意思?

3
ESM相对于CJS的一个主要优势在于,ESM具有并鼓励静态导入依赖项的方式。静态导入大大提高了模块系统的内省能力,因为它们可以在系统中的每个模块的抽象语法树(AST)中被静态地分析和词法提取。

- 《深入浅出模块化JavaScript》by Nicolas Bevacqua

我不理解这个,有人可以帮忙吗?


好的,让我们看看我们能如何帮助您。您不理解哪些部分? - evolutionxbox
2
你不明白其中哪一部分?你知道这里的“analysis”是什么意思吗? - Bergi
一种静态导入依赖的方式,如何解释 - forks Hume
1个回答

13
JavaScript的本地模块系统,有时称为ESM(ECMAScript模块),具有静态和动态导入。它最初只有静态导入(仍然占主导地位),然后通过dynamic import proposal添加了动态导入,现在在浏览器、Node.js和打包工具中得到了完整支持(尽管一些打包工具如果您希望进行树摇,则会添加限制)。
“静态”是什么意思?当您使用import声明时,它必须位于模块的顶层,而不是任何控制流语句之内,并且必须使用字符串文字来说明要从哪个模块进行导入,而不仅仅是一个字符串。这样可以通过静态分析(仅解析代码而不运行)确定模块之间的关系。这是有效的:
import foo from "./mod.js";

那是一个静态导入。

这是无效的:

// Invalid (but keep reading for an alternative)
if (someCondition) {
    import foo from "./mod1.js";
} else {
    import foo from "./mod2.js";
}

也不是这样:

// Invalid (but keep reading for an alternative)
import foo from someCondition ? "./mod1.js" : "./mod2.js";

如果这样做成功了,它将成为一种动态导入; 导入的内容取决于在运行时确定的条件。(JavaScript现在确实有动态导入,只是不用那个语法,请看下文。)
类似地,导出是用静态export声明而不是运行时代码声明的。
CommonJS (CJS,Node.js使用的一种变体)仅具有通过require函数和分配给exports对象的动态导入和导出:
// Valid CommonJS
let foo;
if (someCondition) {
    foo = require("./mod1.js");
} else {
    foo = require("./mod2.js");
}

// or more simply:

const foo = require(someCondition ? "./mod1.js" : "./mod2.js");

因为有一些情况下在运行时确定导入是有用的,所以现在JavaScript也具有动态导入功能,通过类似于函数调用(但不是)的方式实现:{{dynamic import}}。
// Valid ESM (now that dynamic import is done)
import(someCondition ? "./mod1.js" : "./mod2.js")
.then(({default: foo}) => {
    // ...code here using `foo` from either `mod1` or `mod2`...
});
import() 伪函数返回一个 Promise,该 Promise 要么用模块的命名空间对象(其将模块的导出作为属性)来实现,要么被拒绝并带有错误。 import() 特别适合与 顶层 await 结合使用。顶层 await 让您可以像以下方式编写代码:
// Valid ESM (now that dynamic import and top-level `await` are done)
const foo = await import(someCondition ? "./mod1.js" : "./mod2.js").default;
// ...code here using `foo` from either `mod1` or `mod2`...

虽然您始终可以导出具有运行时定义属性的对象,但是目前仍然需要静态定义导出。


看着动态导入的示例,你可能会想:“嘿,他没有留下拒绝处理程序!如果加载模块时出现问题,他将在控制台中得到一个“未处理的拒绝”错误!”是的,我会得到这个错误。它将与已经存在的模块加载错误以及可能导致模块加载失败的网络错误一起显示。这也是静态模块加载失败时会出现的情况(只是没有未处理的拒绝错误)。模块加载失败是一件相当灾难性的事情。 :-) 但是如果你有一些可选内容,你肯定可以处理拒绝:

let localization;
try {
    // Try to get localization information for the user's language...
    localization = import(`./locale-${navigator.language}.js`);
} catch {
    // ...that failed, fall back to default
    localization = import(`./locale-default.js`);
}

(敏锐的人会注意到上面使用了可选 catch 绑定语法。)


(嗯,如果您觉得以上内容有帮助,可以在我的书籍中了解更多关于JavaScript模块加载的知识。) - T.J. Crowder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接