深入了解 Dynamic imports
人生代码
共 2670字,需浏览 6分钟
·
2021-03-10 10:20
深入了解动态导入
我们在前面的章节中提到的导出和导入语句被称为“静态”。语法非常简单和严格。
首先,我们不能动态地生成import
的任何参数。
模块路径必须是原语字符串,不能是函数调用。这不会工作:
import ... from getModuleName(); // Error, only from "string" is allowed
其次,不能有条件地或在运行时导入:
if(...) {
import ...; // Error, not allowed!
}
{
import ...; // Error, we can't put import in any block
}
这是因为import/export
的目的是为代码结构提供一个主干。这是一件好事,因为代码结构可以被分析,模块可以被收集并通过特殊工具绑定到一个文件中,未使用的导出可以被删除(“树状震荡”)。这是可能的,因为进口/出口的结构简单和固定。
但我们如何动态地、按需地导入模块呢?
import() 表达式
import(module)
表达式加载模块并返回一个promise
,该promise
解析为一个包含其所有导出的module
对象。可以从代码中的任何地方调用它。
我们可以在代码的任何地方动态地使用它,例如:
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
或者,如果在异步函数中,也可以使用let module = await import(modulePath)
。
例如,如果我们有以下模块say.js
:
// 📁 say.js
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
那么动态导入可以像这样:
let {hi, bye} = await import('./say.js');
hi();
bye();
或者,如果say.js
有默认的导出:
// 📁 say.js
export default function() {
alert("Module loaded (export default)!");
}
然后,为了访问它,我们可以使用模块对象的default
属性:
let obj = await import('./say.js');
let say = obj.default;
// or, in one line: let {default: say} = await import('./say.js');
say();
下面是完整的例子:
say.js
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
export default function() {
alert("Module loaded (export default)!");
}
index.html
<!doctype html>
<script>
async function load() {
let say = await import('./say.js');
say.hi(); // Hello!
say.bye(); // Bye!
say.default(); // Module loaded (export default)!
}
</script>
<button onclick="load()">Click me</button>
注意
动态导入可以在常规脚本中工作,它们不需要script type="module"
。
尽管import()
看起来像一个函数调用,但它是一种特殊的语法,只是碰巧使用了圆括号(类似于`super()``)。
因此,我们不能将import
复制到一个变量,也不能使用call/apply
。它不是一个函数。
评论