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

标签 javascript

One major advantage in ESM over CJS is how ESM has — and encourages — a way of statically importing dependencies. Static imports vastly improve the introspection capabilities of module systems, given they can be analyzed statically and lexically extracted from the abstract syntax tree (AST) of each module in the system

Mastering Modular JavaScript by Nicolas Bevacqua

我不明白这个,有人可以帮忙吗?

最佳答案

JavaScript 的 native 模块系统,有时称为 ESM (ECMAScript Modules),具有静态和动态导入功能。一开始只是静态导入(仍然占主导地位),然后由 dynamic import proposal 添加了动态导入。 ,现在已经完成,并且在浏览器、Node.js 和 bundler 中得到了良好的支持(尽管有些 bundler 如果您希望它们进行树摇动,则会添加限制)。

“静态”是什么意思?当您使用 import 声明时,它必须位于模块的顶层,位于任何控制流语句之外,并且必须使用字符串literal来说明什么从中导入的模块,而不仅仅是一个字符串。因此,模块之间的关系可以通过静态分析来确定(仅通过解析代码,而不是运行代码)。这是有效的:

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 现在还可以通过看起来像函数调用(但实际上不是)的东西进行动态导入:

// 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()top-level 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`);
}

(眼尖的人会注意到上面使用了 optional catch binding 语法。)

关于javascript - ES6中的静态导入是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52965907/

相关文章:

javascript - 如何使用 Kendo 网格列构建 anchor 链接以在新窗口中打开页面?

c# - 来自 C# 的 javascript unicode 属性

javascript - 图像下的 2 个 div 以填充透明颜色 [html]

javascript - 使用 Redux 创建倒数计时器

javascript - Google Apps 脚本 - 如何中断循环以防止出现错误消息

javascript - 悬停时 HTML 突出显示标签

javascript - 用 req.query 填充数组

javascript - 如何使用jquery文件上传 Angular 版本?

javascript - HTML/JS 中的 iOS 风格滚动

php - 避免两次打开同一页面