В этом руководстве вы узнаете, как динамически импортировать модули с помощью функционального аналога import()
в ES2020 JavaScript.
В 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); }
И используете функцию show()
в app.js
:
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()
принимает спецификатор модуля(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, вы можете использовать async/await в модуле app.js
следующим образом:
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); } })(); });
Практические примеры
import()
имеет следующие практические варианты использования:
1) Загрузка модуля по запросу
Некоторые функции могут быть недоступны при запуске приложений. Чтобы уменьшить время загрузки, вы можете разместить такие функции в модулях и использовать import()
для их загрузки по запросу, например:
function eventHandler() { import('./module1.js') .then((ns) => { // use the module ns.func(); }) .catch((error) => { // handle error }); }
2) Загрузка модулей в зависимости от условий
При размещении import()
внутри условного оператора, такого как if-else, вы можете загружать модули на основе определенного условия. В следующем примере загружается модуль, ориентированный на определенную платформу:
if( isSpecificPlatform() ) { import('./platform.js') .then((ns) => { ns=>f(); }); }
3) Спецификаторы вычисляемого модуля
Спецификатор модуля — это выражение, которое позволяет вам решить, какой модуль загружать во время выполнения.
Например, вы можете загрузить модуль на основе локали пользователя, чтобы показать сообщение на конкретном языке пользователя:
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
обеспечивает доступ к экспорту по умолчанию.