18 / 33
Как работает динамический импорт (import())?
Полный ответ
Статический import разбирается движком до выполнения кода — все зависимости загружаются сразу. Динамический import() работает иначе:
JavaScript
// Статический — загрузится всегда, даже если не нужен
import { heavyChart } from "./chart.js";
// Динамический — загрузится только когда понадобится
const button = document.getElementById("show-chart");
button.addEventListener("click", async () => {
const { heavyChart } = await import("./chart.js");
heavyChart.render();
});
import() возвращает Promise, который резолвится в объект модуля:
JavaScript
// Все экспорты доступны как свойства объекта
const module = await import("./math.js");
console.log(module.add(2, 3)); // именованный экспорт
console.log(module.default); // экспорт по умолчанию (если есть)
// Деструктуризация
const { add, subtract } = await import("./math.js");
Основные сценарии использования:
JavaScript
// 1. Условная загрузка
async function getFormatter(locale) {
if (locale === "ru") {
return await import("./formatters/ru.js");
}
return await import("./formatters/en.js");
}
// 2. Загрузка по маршруту (React lazy)
const AdminPanel = React.lazy(() => import("./AdminPanel"));
function App() {
return (
<Suspense fallback={<Spinner />}>
<AdminPanel />
</Suspense>
);
}
// 3. Загрузка полифиллов только когда нужно
if (!("IntersectionObserver" in window)) {
await import("intersection-observer");
}
// 4. Загрузка по действию пользователя
document.getElementById("export-pdf").addEventListener("click", async () => {
const { generatePDF } = await import("./pdf-generator.js");
generatePDF(document.body);
});
Обработка ошибок:
JavaScript
// ❌ Если модуль не найден — Promise реджектится
try {
const mod = await import("./nonexistent.js");
} catch (error) {
console.error("Модуль не загрузился:", error);
}
// ✅ С fallback
async function loadAnalytics() {
try {
const { track } = await import("./analytics.js");
track("page_view");
} catch {
console.warn("Аналитика недоступна");
}
}
Реальные кейсы
Code splitting в webpack/Vite:
JavaScript
// webpack автоматически создаёт отдельный чанк
const routes = {
"/dashboard": () => import("./pages/Dashboard"),
"/settings": () => import("./pages/Settings"),
"/profile": () => import("./pages/Profile"),
};
async function navigate(path) {
const pageModule = await routes[path]();
pageModule.default.mount(document.getElementById("app"));
}
Типичная ошибка — забыть, что import() асинхронный:
JavaScript
// ❌ module будет Promise, а не модуль
const module = import("./utils.js");
module.doSomething(); // TypeError: module.doSomething is not a function
// ✅ Нужен await или .then()
const module = await import("./utils.js");
module.doSomething();
Резюме
import() даёт ленивую загрузку модулей — код грузится по требованию, а не весь сразу. Это уменьшает начальный бандл, ускоряет первую загрузку страницы и позволяет условно подтягивать зависимости. Бандлеры (webpack, Vite, Rollup) используют import() как границу для разделения кода на чанки.