Основное об Async/await
async
- это ключевое слово, которое ставится перед функцией и указывает, что функция является асинхронной. Функция, помеченная как async
, всегда возвращает промис. Если функция возвращает значение, то оно будет обернуто в промис. Если функция выбрасывает ошибку, то промис будет отклонен с этой ошибкой.
async function getData() {
const response = await fetch("https://example.com/data")
const data = await response.json()
return data
}
await
- это ключевое слово, которое используется внутри функции, помеченной как async
, для ожидания завершения асинхронной операции. Когда операция завершается, await
возвращает результат выполнения операции. Если операция завершается с ошибкой, await
выбрасывает исключение.
async function getData() {
const response = await fetch("https://example.com/data")
const data = await response.json()
return data
}
В данном примере, await
используется для ожидания выполнения асинхронной операции получения данных с сервера. Когда операция завершается, await
возвращает результат выполнения операции.
Использование async
и await
позволяет писать код, который выглядит как синхронный, но при этом выполняется асинхронно. Это делает код более понятным и удобным для чтения и отладки. Кроме того, async
и await
упрощают обработку ошибок в асинхронном коде, так как ошибки могут быть обработаны с помощью конструкции try-catch
.
Async/await
под капотом
Async/await
является синтаксическим сахаром взаимодействия промиса с генераторами.
function* main() {
console.log('Entry');
const result = yield wait();
console.log(result);
const result2 = yield wait();
console.log(result2);
// ...
console.log('Exit');
return 'Return';
}
run(main).then(result => {
console.log(result);
});
function run(fn, ...args) {
const it = fn(...args);
return new Promise((resolve, reject) => {
function step(resolvedValue) {
const result = it.next(resolvedValue);
// Условие выхода
if (result.done) {
resolve(result.value);
return;
}
result.value.then(resolvedValue => {
step(resolvedValue);
});
}
Почему использовать return await
плохая идея?
Правило no-return-await
в ESLint запрещает использование return await
в асинхронной функции. Потому что:
возвращаемое значение асинхронной функции всегда оборачивается в Promise.resolve , то return await
на самом деле ничего не делает, кроме как добавляет дополнительное время, прежде чем Promise закончится resolve или reject .
Верхнеуровневый await
и асинхронные модули
Верхнеуровневый await (top level await) позволяет использовать этот оператор за пределами асинхронных функций:
const connection = await dbConnector()
const jQuery = await import("http://cdn.com/jquery")
_Но его можно использовать только либо внутри ES6-модулей, либо в DevTools. Такое ограничение связано с тем, что await
— это синтаксический сахар, который работает через модули. _
Например, модуль с верхнеуровневым await
для разработчика выглядит так:
// module.mjs
const value = await Promise.resolve("^_^")
export { value }
// main.mjs
import { value } from "./module.mjs"
console.log(value) // ^_^
Ни внутри модуля, ни внутри основной программы нет асинхронных функций, но при этом они необходимы для работы await. Как же тогда работает этот код?
Дело в том, что движок сам возьмёт на себя задачу обернуть await
в асинхронную функцию, поэтому где-то «под капотом», без синтаксического сахара, верхнеуровневый await
будет выглядеть примерно так:
// module.mjs
export let value
export const promise = (async () => {
value = await Promise.resolve("^_^")
})()
export { value, promise }
// main.mjs
import { value, promise } from "./module.mjs"
;(async () => {
await promise
console.log(value) // ^_^
})()
Никакой магии. Просто синтаксический сахар.