Раньше, чтобы использовать await, код нужно было помещать в асинхронную функцию. Это означало, что вы не могли использовать его вне какого-либо обозначения функции. Await верхнего уровня позволяет модулям работать как асинхронные функции.
Модули асинхронны, в них есть импорт и экспорт, которые также выражаются на верхнем уровне. На практике при попытке предоставить модулю, который полагается на какую-то асинхронную задачу, возможность сделать что-то, не существовало действительно хорошего способа реализации.
Await верхнего уровня решает эту проблему и позволяет разработчикам использовать ключевое слово await вне асинхронных функций. С await верхнего уровнямодули ECMAScript могут дожидаться ресурсов, заставляя другие модули, которые их импортируют, ждать, прежде чем они начнут рассчитывать своё тело. Их можно использовать также как запасной вариант зависимости при неудачной загрузке модуля или для загрузки первого скачанного ресурса.
Замечания:
- Awaitверхнего уровня работает только на верхнем уровне модулей. Не существует поддержки для классических скриптов или неасинхронных функций.
- На момент написания этой статьи (23/02/2020) ECMAScript этап 3.
Как использовать
С await верхнего уровня следующий код работает так же, как внутри модулей.
1. Использование запасного варианта при неудачной загрузке модуля
В следующем примере попробуем загрузить модуль JavaScript с first.com, прибегнув к запасному варианту в случае неудачи:
//module.mjs
let module;
try {
module= await import('https://first.com/libs.com/module1');
} catch {
module= await import('https://second.com/libs/module1');
}
2. Использование ресурса с более быстрой загрузкой
Здесь переменную res инициализирует первый скачанный ресурс.
//module.mjs
const resPromises = [
donwloadFromResource1Site,
donwloadFromResource2Site
];
const res = await Promise.any(resPromises);
3. Инициализация ресурса
Await верхнего уровня позволяет вам ожидать промисы в модуле как будто они завёрнуты в асинхронную функцию. Это полезно, например, для инициализации приложений:
//module.mjs
import { dbConnector} from './dbUtils.js'
//connect() возвращает промис.
const connection = await dbConnector.connect();
export default function(){connection.list()}
4. Динамичная загрузка модулей
Позволяет модулям использовать значения времени выполнения для определения зависимостей.
//module.mjs
const params = new URLSearchParams(window.location.search);
const lang = params.get('lang');
const messages = await import(`./messages-${lang}.mjs`);
5. Использование await снаружи асинхронных функций в DevTools?
До async/await попытка использовать await снаружи асинхронной функции приводила к следующему результату: “SyntaxError: await действителен только в асинхронной функции”. Теперь можно использовать await, не находясь внутри асинхронной функции.
Работоспособность проверена в chrome 80 и firefox 72.0.2 DevTools. Однако эта функциональность не является стандартной и не работает в node.js.
const helloPromise = new Promise((resolve)=>{
setTimeout(()=> resolve('Hello world!'), 5000);
})
const result = await helloPromise;console.log(result);
//Через 5 секунд...:
//Hello world!
Реализация
- V8 с пометкой: — — harmony-top-level-await
- Webpack (экспериментальная поддержка в 5.0.0)
- Поддержка парсера добавлена в Babel (babel/plugin-syntax-top-level-await).
Полезные ссылки
- https://github.com/bmeck/top-level-await-talking/
- https://github.com/tc39/proposal-top-level-await#use-cases
Читайте также:
- Чистый код JavaScript — Вертикальное форматирование
- Что значит this в JavaSсript?
- Даты-заглушки в модульных тестах на JavaSсript
Перевод статьи Kesk Noren: How the new ‘Top Level Await’ feature works in JavaScript