Skip to content
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() как границу для разделения кода на чанки.

Как работает динамический импорт (import())? | JScriptiser