动态 import()
动态 import()
https://v8.dev/features/dynamic-import
Dynamic import() 引入了一个新的类似函数的功能,相比静态的 import
提供了新的功能。本文比较这两个特性,并提供了新功能的介绍。
静态 import (回顾)
在 Chrome 61 中提供了对于 ES2015 的 modules
中 import
语句的支持。
考虑如下 module,它位于地址 ./utils.mjs
// Default export
export default () => {
console.log('Hi from the default export!');
};
// Named export `doStuff`
export const doStuff = () => {
console.log('Doing stuff…');
};
如下代码演示如何使用静态导入,并使用 ./util.mjs
模块。
<script type="module">
import * as module from './utils.mjs';
module.default();
// → logs 'Hi from the default export!'
module.doStuff();
// → logs 'Doing stuff…'
</script>
注意
在上述示例中,使用了.mjs
扩展名来表示这个一个模块,而不是常规的脚本。
在 Web 中,文件的扩展名并不重要,只要在 Content-Type 响应头中使用了正确的 MIME 类型即可 ( 例如,对于 JavaScript 文件来说,为 text/javascript) 。
.mjs
扩展名对于其它平台特别有用,比如 Node.js 和 d8,因为在这些环境中,没有 MIME 的支持或者其它强制的要求,例如type="module"
来检测它到底是模块还是常规的脚本。我们这里使用.mjs
扩展名来实现跨平台的一致性,并清楚地区分模块和常规脚本。
这里使用的导入模块方式就是 静态 定义:它只接受一个字面字符串作为模块的指示器,通过链接过程将绑定引入到本地范围。静态的 import
语法只能用于文件的顶级。
静态 import
支持重要的使用场景,例如静态分析,打包工具以及摇树操作。
对于有些场景,需要支持:
- 按需加载模块 ( 或者有条件 )
- 在运行时得到模块的指示符
- 从常规的脚本 ( 不是模块) 中加载模块
这些需求都不能通过静态 import
得到。
动态 import()
Dynamic import() 引入了 import
的新特性来处理这些场景。import(moduleSpecifier)
返回请求模块的模块对象的一个 Promise。它将在获取之后创建,并检查该模块所有的依赖,以及该模块本身。
这里是如何使用动态 import()
来加载 ./utils.mjs
模块。
<script type="module">
const moduleSpecifier = './utils.mjs';
import(moduleSpecifier)
.then((module) => {
module.default();
// → logs 'Hi from the default export!'
module.doStuff();
// → logs 'Doing stuff…'
});
</script>
由于 import()
返回一个 Promise,就可以使用 async/await
来代替 Promise 的 then()
调用风格。
<script type="module">
(async () => {
const moduleSpecifier = './utils.mjs';
const module = await import(moduleSpecifier)
module.default();
// → logs 'Hi from the default export!'
module.doStuff();
// → logs 'Doing stuff…'
})();
</script>
注意
尽管import()
看起来类似一个函数调用,实际上它是一个语法,只是使用了圆括号而已,类似 super()。这意味着import()
的原型并不是Function.prototype
,所以你也不能对它使用call()
或者apply()
。
类似语法也不能工作const importAlias = import
,甚至,import
都不是一个对象!尽管在实践中并不重要。
这里是一个使用动态 import()
来实现延迟加载模块的示例,基于一个小型的 SPA 应用的导航。
<!DOCTYPE html>
<meta charset="utf-8">
<title>My library</title>
<nav>
<a href="books.html" data-entry-module="books">Books</a>
<a href="movies.html" data-entry-module="movies">Movies</a>
<a href="video-games.html" data-entry-module="video-games">Video Games</a>
</nav>
<main>This is a placeholder for the content that will be loaded on-demand.</main>
<script>
const main = document.querySelector('main');
const links = document.querySelectorAll('nav > a');
for (const link of links) {
link.addEventListener('click', async (event) => {
event.preventDefault();
try {
const module = await import(`/${link.dataset.entryModule}.mjs`);
// The module exports a function named `loadPageInto`.
module.loadPageInto(main);
} catch (error) {
main.textContent = error.message;
}
});
}
</script>
当正确使用的时候,使用动态 import()
来实现延迟加载可以非常强大,为了演示目的,Addy 创建了 an example Hacker News PWA,其中使用静态导入所有依赖的模块,在第一次加载的时候加载留言。更新后的版本 使用动态 import()
来延迟加载留言,避免了加载、解析和编译的代价,直到用户需要才会处理。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2013-04-14 云中漫步 - 3:2013-4-27 微软云体验营北京站