Перейти к содержимому

Top-level await

Top-level await (TC39 Stage 4, ES2022) позволяет использовать await на верхнем уровне ESM-модуля — импортирующий модуль неявно ожидает завершения, что меняет граф загрузки и важно понимать при бандлинге и серверном рендеринге.

db.mjs
// ДО TLA: экспорт промиса или init-функции — неудобно
// export const dbPromise = connectToDatabase();
// ПОСЛЕ: top-level await — db уже готов при импорте
const db = await connectToDatabase(); // блокирует загрузку модуля
export { db };
// Использование в app.mjs:
import { db } from './db.mjs';
// Гарантировано: db инициализирован до начала выполнения app.mjs
console.log(db.status); // 'connected'
a.mjs
// Граф зависимостей при TLA
export const config = await fetch('/config').then(r => r.json());
// b.mjs импортирует a.mjs → b ЖДЁТ пока a завершит TLA
import { config } from './a.mjs';
console.log(config.version); // уже доступен
// Параллельная загрузка независимых модулей:
// e.mjs импортирует и c.mjs и d.mjs (оба с TLA)
// import './c.mjs'; import './d.mjs';
// → TLA в c и d выполняются параллельно (как Promise.all)
// → e ждёт завершения обоих
// Практика: conditional polyfill / feature detection
const { default: nodeFetch } = await (
typeof globalThis.fetch === 'undefined'
? import('node-fetch')
: { default: globalThis.fetch }
);
// Dynamic config с fallback
const config = await (async () => {
try {
return (await import('./config.local.json', { assert: { type: 'json' } })).default;
} catch {
return (await import('./config.default.json', { assert: { type: 'json' } })).default;
}
})();
// TLA работает только в .mjs или "type": "module"
// В .cjs → SyntaxError

Итог: Top-level await превращает ESM-модуль в асинхронный участник графа зависимостей; все импортирующие его модули неявно ожидают завершения TLA, а параллельные TLA-модули выполняются параллельно.