在本教程中,您将学习如何使用 ES2020 的函数 import()
动态导入模块。
JavaScript import() 简介
ES6 引入模块概念,允许您开发模块化 JavaScript 代码。假设您有以下具有一个按钮的简单 HTML 文档:
<!DOCTYPE html>
<html>
<head>
<title>Module Dynamic Import</title>
</head>
<body>
<button id="show">Show Dialog</button>
<script type="module" src="js/app.js"></script>
</body>
</html>
当用户单击按钮时,您希望显示一个对话框。为了使代码更有条理,您开发了一个名为的 dialog.js
模块:
export function show(message) {
alert(message);
}
并在 app.js
使用 show()
函数:
import {show} from './dialog.js';
let btn = document.querySelector('#show');
btn.addEventListener('click', function () {
show('Hi');
});
在 ES2020 之前,无法在需要时动态加载 dialog.js
模块。下面的代码将会导致错误:
let btn = document.querySelector('#show');
btn.addEventListener('click', function () {
import {show} from './dialog.js';
show('Hi');
});
上面的代码仅在单击按钮时才尝试加载 dialog.js
模块。
在 ES2020 通过类函数 import()
引入模块的动态导入,语法如下:
import(moduleSpecifier);
import()
允许您在需要时动态导入模块。import()
工作原理如下:
import()
接受模块说明符moduleSpecifier
,其格式与import
语句的模块说明符相同。此外,moduleSpecifier
可以是评估为字符串的表达式。import()
返回一个Promise
将在模块完全完成加载后返回值。
要动态加载 dialog.js
,您可以使用 import()
,如下方法:
let btn = document.querySelector('#show');
btn.addEventListener('click', function() {
import('./dialog.js')
.then(( dialog ) => {
dialog.show();
})
.catch( error => {
// handle error here
});
});
由于 import()
返回一个 Promise ,您可以像这样在 app.js
模块中使用 async / await :
let btn = document.querySelector('#show');
btn.addEventListener('click', function () {
(async () => {
try {
let dialog = await import('./dialog.js');
dialog.show('Hi')
} catch (error) {
console.log(error);
}
})();
});
JavaScript import 实际用例
按需加载模块
应用程序启动时,某些功能可能不需要可用。为了减少加载时间,您可以将此类功能放在模块中并使用 import()
按需加载它们,如下所示:
function eventHandler() {
import('./module1.js')
.then((ns) => {
// use the module
ns.func();
})
.catch((error) => {
// handle error
});
}
根据条件加载模块
将 import()
语句放在 if-else 等条件语句里面,就可以根据指定的条件加载模块。以下示例加载一个针对指定平台的模块:
if( isSpecificPlatform() ) {
import('./platform.js')
.then((ns) => {
ns=>f();
});
}
计算模块说明符
模块说明符是一个表达式,允许您决定在运行时加载哪个模块。例如,您可以根据用户的语言环境加载模块,以用户的语言展示消息:
let lang = `message_${getUserLocale()}.js`;
import(lang)
.then(...);
使用对象解构
如果一个模块有多个导出,您可以使用对象解构来接收导出对象。假设dialog.js
有两个函数:
export function show(message) {
alert(message);
}
export function hide(message) {
console.log('Hide it...');
}
在 app.js
,您可以按如下方式使用对象解构:
let btn = document.querySelector('#show');
btn.addEventListener('click', function () {
(async () => {
try {
// use object destructuring
let {
show,
hide
} = await import('./dialog.js');
// use the functions
show('Hi');
hide();
} catch (err) {
console.log(err);
}
})();
});
动态加载多个模块
要动态加载多个模块,可以使用 Promise.all()
方法:
Promise.all([
import(module1),
import(module2),
...])
.then(([module1,module2,module3]) => {
// use the modules
});
访问默认导出
如果模块有默认导出,您可以使用 default
关键字访问它。例如:
import(moduleSpecifier)
.then((module) => {
// access the default export
console.log(module.default);
});
结论
- 使用 JavaScript
import()
动态加载模块。import()
返回一个Promise
将在模块加载后完成后返回值。 - 使用
async
/await
来处理import()
. - 使用
Promise.all()
方法一次加载多个模块。 - 使用对象解构将变量分配给模块的导出对象。
- 使用
default
关键字访问默认导出。