import()
Базовый уровень Широко доступен
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с мая 2018 года.
Синтаксис import(), обычно называемый динамическим импортом, представляет собой выражение, похожее на функцию, которое позволяет асинхронно и динамически загружать модуль ECMAScript в потенциально немодульную среду.
В отличие от своего декларативного аналога, динамические импорты вычисляются только тогда, когда это необходимо, и обеспечивают большую синтаксическую гибкость.
Синтаксис
import(moduleName) import(moduleName, options)
Вызов import() представляет собой синтаксис, который очень напоминает вызов функции, но сам import является ключевым словом, а не функцией. Вы не можете создать для него псевдоним, как для const myImport = import, что вызовет SyntaxError.
Конечные запятые разрешены, только если среда выполнения также поддерживает options. Проверьте совместимость с браузерами.
Параметры
-
moduleName - Модуль для импорта. Вычисление спецификатора определяется хостом, но всегда соответствует тому же алгоритму, что и статические объявления импорта.
-
options - Объект, содержащий параметры импорта. Распознается следующий ключ:
-
with - Атрибуты импорта.
-
Возвращаемое значение
Возвращает промис, который:
- Если модуль, на который ссылаются, успешно загружен и вычислен, он разрешается в объект пространства имен модуля: объект, содержащий все экспорты из
moduleName. - Если приведение к строке
moduleNameвызывает ошибку, промис отклоняется с этой ошибкой. - Если извлечение и загрузка модуля завершаются неудачей по любой причине, промис отклоняется с ошибкой, определенной реализацией (Node использует общую
Error, тогда как все браузеры используютTypeError). Распространенные причины могут включать:- В модульной системе, основанной на файловой системе (например, Node.js), если доступ к файловой системе завершается неудачей (отказано в доступе, файл не найден и т. д.).
- В модульной системе, основанной на веб-технологиях (например, браузеры), если сетевой запрос завершается неудачей (нет подключения к Интернету, проблема CORS и т. д.) или возникает ошибка HTTP (404, 500 и т. д.).
- Если вычисление модуля, на который ссылаются, вызывает ошибку, промис отклоняется с этой ошибкой.
Примечание: import() никогда синхронно не выбрасывает ошибку.
Описание
Синтаксис объявления импорта (import something from "somewhere") является статическим и всегда приводит к вычислению импортируемого модуля во время загрузки. Динамический импорт позволяет обойти синтаксическую жесткость объявлений импорта и загружать модуль условно или по требованию. Ниже приведены некоторые причины, по которым вам может потребоваться использовать динамический импорт:
- Когда статическое импортирование значительно замедляет загрузку вашего кода или увеличивает использование памяти вашей программы, и при этом низка вероятность того, что вам понадобится импортируемый код, или он понадобится вам только позже.
- Когда импортируемый вами модуль не существует во время загрузки.
- Когда строка спецификатора импорта должна быть построена динамически. (Статический импорт поддерживает только статические спецификаторы.)
- Когда импортируемый модуль имеет побочные эффекты, и вы не хотите этих побочных эффектов, если не выполняется какое-либо условие. (Рекомендуется не иметь побочных эффектов в модуле, но иногда вы не можете контролировать это в зависимостях вашего модуля.)
- Когда вы находитесь в немодульной среде (например,
evalили в файле скрипта).
Используйте динамический импорт только при необходимости. Статическая форма предпочтительна для загрузки начальных зависимостей и может легче извлекать выгоду из инструментов статического анализа и tree shaking.
Если ваш файл не запускается как модуль (если на него есть ссылка в файле HTML, тег скрипта должен иметь type="module"), вы не сможете использовать статические объявления импорта. С другой стороны, асинхронный синтаксис динамического импорта всегда доступен, что позволяет импортировать модули в немодульные среды.
Параметр options позволяет использовать различные типы параметров импорта. Например, атрибуты импорта:
import("./data.json", { with: { type: "json" } });
Динамический импорт модулей разрешен не во всех контекстах выполнения. Например, import() можно использовать в основном потоке, общем воркере или выделенном воркере, но он выдаст ошибку, если будет вызван в service worker или worklet.
«Модификаторы фаз» для операторов import также могут использоваться с динамическими импортами:
Каждый из этих синтаксисов считается отдельным типом выражения.
Объект пространства имен модуля
Объект пространства имен модуля — это объект, который описывает все экспорты из модуля. Это статический объект, который создается при вычислении модуля. Существует два способа доступа к объекту пространства имен модуля: через импорт пространства имен (import * as name from moduleName) или через значение исполнения динамического импорта.
Объект пространства имен модуля является запечатанным объектом с прототипом null. Это означает, что все строковые ключи объекта соответствуют экспортам модуля, и никогда не бывает лишних ключей. Все ключи перечисляемы в лексикографическом порядке (т. е. стандартное поведение Array.prototype.sort()), при этом экспорт по умолчанию доступен как ключ с именем default. Кроме того, объект пространства имен модуля имеет свойство [Symbol.toStringTag] со значением "Module", используемое в Object.prototype.toString().
Строковые свойства являются ненастраиваемыми (non-configurable) и записываемыми (writable), когда вы используете Object.getOwnPropertyDescriptors() для получения их дескрипторов. Однако они фактически доступны только для чтения, потому что вы не можете переназначить свойству новое значение. Такое поведение отражает тот факт, что статические импорты создают «динамические привязки» (live bindings) — значения могут быть переназначены модулем, который их экспортирует, но не модулем, который их импортирует. Возможность записи свойств отражает возможность изменения значений, поскольку ненастраиваемые и незаписываемые свойства должны быть константами. Например, вы можете переназначить экспортированное значение переменной, и новое значение будет видно в объекте пространства имен модуля.
Каждый (нормализованный) спецификатор модуля соответствует уникальному объекту пространства имен модуля, поэтому, как правило, верно следующее:
import * as mod from "/my-module.js";
import("/my-module.js").then((mod2) => {
console.log(mod === mod2); // true
});
За исключением одного любопытного случая: поскольку промис никогда не разрешается в thenable, если модуль my-module.js экспортирует функцию с именем then(), эта функция будет автоматически вызвана при выполнении промиса динамического импорта, как часть процесса разрешения промиса.
// my-module.js
export function then(resolve) {
console.log("then() called");
resolve(1);
}
// main.js
import * as mod from "/my-module.js";
import("/my-module.js").then((mod2) => {
// Logs "then() called"
console.log(mod === mod2); // false
});
Предупреждение: Не экспортируйте функцию с именем then() из модуля. Это приведет к тому, что модуль будет вести себя иначе при динамическом импорте, чем при статическом.
Это агрессивное кэширование гарантирует, что фрагмент кода JavaScript никогда не будет выполнен более одного раза, даже если он импортируется многократно. Будущие импорты даже не приводят к HTTP-запросам или доступу к диску. Если вам необходимо повторно импортировать и повторно вычислить модуль без перезапуска всей среды JavaScript, один из возможных приемов — использовать уникальный параметр запроса в спецификаторе модуля. Это работает и в средах выполнения, не являющихся браузерами, которые также поддерживают спецификаторы URL.
import(`/my-module.js?t=${Date.now()}`);
Обратите внимание, что это может привести к утечкам памяти в долго работающем приложении, поскольку движок не может безопасно выполнить сборку мусора для объектов пространства имен модулей. В настоящее время нет способа вручную очистить кеш объектов пространства имен модулей.
Вы также можете использовать Fetch API для получения исходного кода модуля в виде текста, а затем вручную вычислить модуль в зависимости от типа модуля:
- Для модулей JavaScript вы можете динамически импортировать исходный код в виде URL-адреса
blob:в браузерах или использоватьvm.Moduleдля его вычисления в Node.js. - Для модулей JSON вы можете проанализировать исходный код с помощью
JSON.parse(). - Для модулей CSS вы можете создать новый объект
CSSStyleSheetи использовать его методreplace()для заполнения его исходным кодом.
Однако семантически это не то же самое, что динамический импорт, поскольку настройки пользовательского агента, такие как цель извлечения (fetch destination), CSP или разрешение модулей, могут быть применены некорректно.
Кэширование объектов пространства имен модуля применяется только к модулям, которые были успешно загружены и связаны. Импорт модуля происходит в три этапа: загрузка (извлечение модуля), связывание (в основном, синтаксический анализ модуля) и вычисление (выполнение проанализированного кода). Кэшируются только ошибки вычисления; если модуль не загружается или не связывается, следующий импорт может попытаться загрузить и связать модуль снова. Браузер может кэшировать или не кэшировать результат операции выборки, но он должен следовать типичной семантике HTTP, поэтому обработка таких сетевых сбоев не должна отличаться от обработки сбоев fetch().
Примеры
Импорт модуля только ради его побочных эффектов
(async () => {
if (somethingIsTrue) {
// import module for side effects
await import("/modules/my-module.js");
}
})();
Если ваш проект использует пакеты, экспортирующие ESM, вы также можете импортировать их только ради побочных эффектов. Это запустит код только в файле точки входа пакета (и любых файлах, которые он импортирует).
Импорт значений по умолчанию
Если вы деструктурируете импортированный объект пространства имен модуля, вы должны переименовать ключ default, поскольку default является зарезервированным словом.
(async () => {
if (somethingIsTrue) {
const {
default: myDefault,
foo,
bar,
} = await import("/modules/my-module.js");
}
})();
Импорт по требованию в ответ на действие пользователя
Этот пример показывает, как загрузить функциональность на страницу на основе действия пользователя, в данном случае нажатия кнопки, а затем вызвать функцию внутри этого модуля. Это не единственный способ реализовать эту функциональность. Функция import() также поддерживает await.
const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
link.addEventListener("click", (e) => {
e.preventDefault();
import("/modules/my-module.js")
.then((module) => {
module.loadPageInto(main);
})
.catch((err) => {
main.textContent = err.message;
});
});
}
Импорт различных модулей в зависимости от окружения
В таких процессах, как рендеринг на стороне сервера, вам может потребоваться загрузить различную логику на сервере или в браузере, поскольку они взаимодействуют с разными глобальными переменными или модулями (например, код браузера имеет доступ к веб-API, таким как document и navigator, тогда как код сервера имеет доступ к файловой системе сервера). Вы можете сделать это с помощью условного динамического импорта.
let myModule;
if (typeof window === "undefined") {
myModule = await import("module-used-on-server");
} else {
myModule = await import("module-used-in-browser");
}
Импорт модулей с нелитеральным спецификатором
Динамический импорт позволяет использовать любое выражение в качестве спецификатора модуля, а не обязательно строковые литералы.
Здесь мы загружаем 10 модулей: /modules/module-0.js, /modules/module-1.js и т. д. — одновременно и вызываем функции load, которые экспортирует каждый из них.
Promise.all(
Array.from({ length: 10 }).map(
(_, index) => import(`/modules/module-${index}.js`),
),
).then((modules) => modules.forEach((module) => module.load()));
Использование атрибутов импорта с динамическим импортом
Атрибуты импорта принимаются в качестве второго параметра синтаксиса import().
const data = await import("./data.json", {
with: { type: "json" },
});
Спецификации
Совместимость с браузерами
| Десктопные | Мобильные | Серверные | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox для Android | Opera для Android | Safari на iOS | Samsung Internet | WebView Android | WebView на iOS | Bun | Deno | Node.js | |
import |
63 |
79 |
67 |
50 |
11.1 |
63 |
67 |
46 |
11.3 |
8.0 |
63 |
11.3 |
1.0.0 |
1.0Скомпилированные приложения Deno (с использованиемdeno compile) не поддерживают динамический импорт |
13.2.0Динамическийimport может использоваться как в файлах CommonJS, так и в файлах модулей ES для импорта файлов CommonJS или модулей ES. Дополнительные сведения см. в документации Node по модулям ECMAScript.12.17.0–13.0.0Динамическийimport может использоваться как в файлах CommonJS, так и в файлах модулей ES для импорта файлов CommonJS или модулей ES. Дополнительные сведения см. в документации Node по модулям ECMAScript. |
options_parameter |
91 |
91 |
138 |
77 |
15 |
91 |
138 |
64 |
15 |
16.0 |
91 |
15 |
1.1.5 |
1.17 |
17.5.0
16.15.0–17.0.0
16.14.0–16.15.0Второй параметр больше не вызывает ошибку парсера, но для загрузки модулей JSON по-прежнему требуется флаг--experimental-json-modules. |
worker_support |
80 |
80 |
114 |
67 |
15 |
80 |
114 |
57 |
15 |
13.0 |
80 |
15 |
1.0.0 |
1.0 |
13.2.0
12.17.0–13.0.0
|
Смотрите также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import