摘要: 本教程将介绍 JavaScript 动态导入以及如何使用它动态导入模块。
JavaScript 动态导入简介
ES6 引入了模块的概念,允许您开发模块化的 JavaScript 代码。让我们从一个简单的例子开始,了解 JavaScript 动态导入的工作原理。
假设我们有一个项目,结构如下
├── index.html
└── js
├── app.js
└── greeting.js
Code language: plaintext (plaintext)
index.html
从 js
目录加载 app.js
文件。index.html
包含一个按钮,如果单击按钮,则显示一个警报。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Dynamic Import</title>
</head>
<body>
<input type="button" value="Click Me" class="btn">
<script src="js/app.js" type="module"></script>
</body>
</html>
Code language: HTML, XML (xml)
greeting.js
模块定义了一个 sayHi()
函数,并使用命名导出导出它。
export function sayHi() {
alert('Hi');
}
Code language: JavaScript (javascript)
app.js
模块从 greeting.js
模块导入 sayHi
函数。它选择具有类 .btn
的按钮,并在单击按钮时调用 sayHi()
函数。
import sayHi from './greeting.js';
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
sayHi();
});
Code language: JavaScript (javascript)
在 ES2020 之前,无法在需要时动态加载 greeting.js
模块。
例如,以下 app.js
模块尝试仅在单击按钮时加载 greeting.js
模块,并导致错误。
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
import sayHi from './greeting.js'; // ERROR
sayHi();
});
Code language: JavaScript (javascript)
ES2020 通过类似函数的 import()
引入了模块的动态导入,语法如下
import(moduleSpecifier);
Code language: JavaScript (javascript)
import()
允许您在需要时动态导入模块。
以下是 import()
的工作原理
import()
接受一个模块说明符 (moduleSpecifier
),它与用于import
语句的模块说明符具有相同的格式。此外,moduleSpecifier
可以是一个表达式,该表达式计算为字符串。import()
返回一个Promise,该 Promise 在模块完全加载后将被兑现。
以下说明如何使用 import()
语法从 app.js
模块动态加载 greeting.js
模块。
const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
import('./greeting.js')
.then((greeting) => {
greeting.sayHi();
})
.catch((error) => {
console.error(error);
});
});
Code language: JavaScript (javascript)
由于 import()
返回一个Promise,因此您可以在 app.js
模块中使用 async/await,如下所示
const btn = document.querySelector('.btn');
btn.addEventListener('click', async () => {
try {
let greeting = await import('./greeting.js');
greeting.sayHi();
} catch (error) {
console.log(error);
}
});
Code language: JavaScript (javascript)
JavaScript import() 的一些实际用例
import()
具有以下实际用例
1) 按需加载模块
某些模块可能不需要在应用程序启动时可用。为了提高加载时间,您可以将此类功能放在模块中,并使用 import()
按需加载它们,如下所示
function eventHandler() {
import('./module1.js')
.then((ns) => {
// use the module
ns.func();
})
.catch((error) => {
// handle error
});
}
Code language: JavaScript (javascript)
2) 根据条件加载模块
当将 import()
放在条件语句(如 if-else)中时,您可以根据特定条件加载模块。
以下示例加载针对特定平台的模块
if( isSpecificPlatform() ) {
import('./platform.js')
.then((ns) => {
ns=>f();
});
}
Code language: JavaScript (javascript)
3) 计算模块说明符
模块说明符是一个表达式,允许您在运行时决定要加载哪个模块。
例如,您可以根据用户的区域设置加载模块,以显示用户特定语言的消息。
let lang = `message_${getUserLocale()}.js`;
import(lang)
.then(...);
Code language: JavaScript (javascript)
更多关于 import()
使用对象解构
如果一个模块具有多个命名导出,您可以使用 对象解构 来接收导出对象。假设 greeting.js
有两个函数
export function sayHi() {
alert('Hi');
}
export function bye() {
alert('Bye');
}
Code language: JavaScript (javascript)
在 app.js
中,您可以使用 对象解构 如下所示
const btn = document.querySelector('.btn');
btn.addEventListener('click', async () => {
try {
let { sayHi, bye } = await import('./greeting.js');
sayHi();
bye();
} catch (error) {
console.log(error);
}
});
Code language: JavaScript (javascript)
动态加载多个模块
要动态加载多个模块,可以使用 Promise.all()
方法。
Promise.all([
import(module1),
import(module2),
...])
.then(([module1,module2,module3]) => {
// use the modules
});
Code language: JavaScript (javascript)
访问默认导出
如果一个模块具有默认导出,您可以使用 default
关键字访问它,如下所示
import(moduleSpecifier)
.then((module) => {
// access the default export
console.log(module.default);
});
Code language: JavaScript (javascript)
例如,我们可以将命名导出更改为默认导出
export default function sayHi() {
alert('Hi');
}
Code language: JavaScript (javascript)
在 app.js
文件中,我们可以使用模块说明符导入 sayHi
函数,并使用 default
关键字调用 sayHi()
函数。
const btn = document.querySelector('.btn');
btn.addEventListener('click', async () => {
try {
let greeting = await import('./greeting.js');
greeting.default();
} catch (error) {
console.log(error);
}
});
Code language: JavaScript (javascript)
总结
- 使用 JavaScript
import()
动态加载模块。 import()
返回一个Promise
,该 Promise 在模块完全加载后将被兑现。- 使用
async
/await
处理import()
的结果。 - 使用
Promise.all()
方法一次加载多个模块。 - 使用对象解构将变量分配给模块的导出对象。
- 使用
default
关键字访问默认导出。