Динамический import()

Динамический import() #

import() — функция, возвращающая промис с модулем. В отличие от статического import, её можно вызывать в runtime: по условию, по событию, после задержки. Это основа ленивой загрузки и разбиения бандла на чанки.


Синтаксис и результат #

const spec = './admin/reports.js'

import(spec).then((module) => {
  module.renderSalesChart()
})

Выражение в скобках — строка с URL модуля (часто переменная). Результат — промис, который fulfilled с namespace object модуля:

  • именованные экспорты — свойства объекта (module.formatMoney);
  • default — module.default.
import('./playlist-editor.js').then((mod) => {
  const Editor = mod.default
  const { MAX_TRACKS } = mod
  new Editor({ limit: MAX_TRACKS })
})

С await:

async function openEditor() {
  const mod = await import('./playlist-editor.js')
  return new mod.default()
}

Условная загрузка #

Статический import нельзя обернуть в if на верхнем уровне. Динамический — можно:

async function loadCheckoutExtras(role) {
  if (role === 'admin') {
    const admin = await import('./checkout/admin-tools.js')
    admin.mountRefundPanel()
  }
  const core = await import('./checkout/summary.js')
  core.renderTotals()
}

Код admin-tools.js не загрузится и не выполнится для обычного пользователя — меньше байт и поверхность инициализации.


Ленивые маршруты и вкладки #

Типичный UI-паттерн — подгрузка панели при первом открытии:

const tabLoaders = {
  playlist: () => import('./tabs/playlist.js'),
  billing: () => import('./tabs/billing.js'),
}

async function showTab(name) {
  const loader = tabLoaders[name]
  if (!loader) return

  const panel = await loader()
  panel.mount(document.getElementById('tab-root'))
}

Повторный import('./tabs/playlist.js') вернёт тот же закэшированный модуль — сеть не дергается второй раз.


Обработка ошибок #

Сбой сети или 404 отклоняют промис:

async function safeLoad(path) {
  try {
    return await import(path)
  } catch (err) {
    console.error('Модуль не загрузился:', path, err)
    return null
  }
}

Показывайте запасной UI, не оставляйте необработанный reject.


import() vs статический import #

import { x } from './m.js'import('./m.js')
Когда анализируетсядо выполнения (фаза загрузки)при вызове
Где допустимверхний уровень модулявнутри функций, веток
Возвращаетпривязки напрямуюпромис с namespace
Бандлервсегда в графе зависимостейотдельный чанк (обычно)

Оба формата совместимы в одном проекте: критичный путь — статически, редкие экраны — import().


Замечание о переменной в пути #

const chunk = 'heavy-chart'
import(`./widgets/${chunk}.js`) // работает в сборщиках с ограниченным набором шаблонов

Слишком свободная подстановка мешает статическому анализу — бандлеры требуют предсказуемых префиксов. В чистом браузере без сборки предпочитайте полные строковые литералы.


Итог #

  • import() возвращает промис с модулем и выполняется по требованию.
  • Условная и отложенная загрузка снижает начальный объём кода.
  • Повторные вызовы с тем же URL используют кэш модуля.
  • Ошибки загрузки обрабатывайте через .catch или try/catch с await.

См. также #