async и await
Цепочки из then() быстро становятся громоздкими. Ключевые слова async и await позволяют писать асинхронный код как обычный: сверху вниз, строка за строкой. Внутри это те же промисы, просто записанные короче.
await
Слово await перед промисом приостанавливает код, пока промис не выполнится, и возвращает его результат:
const value = await Promise.resolve(42);
console.log(value); // 42Результат лежит в обычной переменной — без then() и вложенной функции.
async
Внутри функций await работает, только если функция объявлена со словом async. Такая функция всегда возвращает промис, даже если в ней написано return 42:
async function getAnswer() {
return 42;
}
const answer = await getAnswer();
console.log(answer); // 42await можно писать и вне функций — в модулях и в примерах на этом сайте. В обычном скрипте браузера вне функции он не работает.
Ожидание по шагам
Когда действий несколько, код с await читается как простая последовательность:
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function cook() {
console.log('Ставим чайник');
await wait(500);
console.log('Чайник вскипел');
await wait(300);
console.log('Чай готов');
}
await cook();
// Ставим чайник
// Чайник вскипел
// Чай готовКаждый await ждёт свой промис, но страница при этом не зависает: пока функция ждёт, выполняется другой код.
Ошибки
Если промис отклонён, await выбрасывает ошибку как обычный throw. Перехватывают её через try...catch:
async function load() {
throw new Error('Сервер не отвечает');
}
try {
await load();
} catch (error) {
console.log(error.message); // Сервер не отвечает
}Блок finally тоже работает: он выполнится и после успеха, и после ошибки.
Одновременное выполнение
await друг за другом выполняет действия по очереди. Если они не зависят друг от друга, быстрее запустить их все сразу и дождаться через Promise.all():
const wait = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));
const start = Date.now();
const [first, second] = await Promise.all([wait('а', 300), wait('б', 300)]);
console.log(first, second); // а б
console.log(Date.now() - start < 500); // trueДва ожидания по 300 мс заняли около 300 мс, а не 600.
async-функция возвращает промис
Результат async-функции можно получить и через then() — это обычный промис. Так делают там, где await недоступен:
async function getName() {
return 'Анна';
}
getName().then((name) => console.log(name)); // АннаЧастая ошибка
Если забыть await, в переменной окажется промис, а не результат:
async function getAnswer() {
return 42;
}
const answer = getAnswer();
console.log(answer instanceof Promise); // true
console.log(answer + 1); // [object Promise]1Ошибки нет, программа просто работает неправильно — поэтому такую оплошность трудно заметить.