JavaScript 动态导入

摘要: 本教程将介绍 JavaScript 动态导入以及如何使用它动态导入模块。

JavaScript 动态导入简介

ES6 引入了模块的概念,允许您开发模块化的 JavaScript 代码。让我们从一个简单的例子开始,了解 JavaScript 动态导入的工作原理。

假设我们有一个项目,结构如下

├── index.html
└── js
   ├── app.js
   └── greeting.jsCode language: plaintext (plaintext)

index.htmljs 目录加载 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 关键字访问默认导出。
本教程对您有帮助吗?