Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

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); // 42

await можно писать и вне функций — в модулях и в примерах на этом сайте. В обычном скрипте браузера вне функции он не работает.

Ожидание по шагам

Когда действий несколько, код с 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

Ошибки нет, программа просто работает неправильно — поэтому такую оплошность трудно заметить.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.