ESM相对于CJS的一个主要优势在于,ESM具有并鼓励静态导入依赖项的方式。静态导入大大提高了模块系统的内省能力,因为它们可以在系统中的每个模块的抽象语法树(AST)中被静态地分析和词法提取。
- 《深入浅出模块化JavaScript》by Nicolas Bevacqua
我不理解这个,有人可以帮忙吗?
- 《深入浅出模块化JavaScript》by Nicolas Bevacqua
我不理解这个,有人可以帮忙吗?
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";
// 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");
// 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
绑定语法。)