Node.js async/await

В Node.js,async/awaitявляется синтаксическим сахаром для обработки асинхронных операций.

async/awaitОн основан на Promise, но заставляет асинхронный код выглядеть более похожим на синхронный код, значительно улучшая читаемость и сопровождаемость кода.

asyncключевое слово используется для объявления функции как асинхронной, иawaitключевое слово используется для ожидания разрешения или отклонения Promise.

Использованиеasync/awaitпозволяет избежать ада обратных вызовов и сделать обработку ошибок более интуитивной.

JavaScript является однопоточным. При встрече с асинхронными задачами (такими как setTimeout или сетевые запросы) он передаёт их API браузера, а по завершении помещает обратный вызов в очередь сообщений.

Цикл событий постоянно проверяет, пуст ли стек вызовов. Если он пуст, он берёт обратный вызов из очереди и помещает его в стек вызовов для выполнения. Это предотвращает блокировку главного потока при обработке асинхронных результатов по порядку.


Базовый синтаксис

асинхронные функции

Любую функцию можно сделать асинхронной, добавивasyncключевое слово:

async function myFunction() {
  return "Hello World";
}

asyncАсинхронная функция всегда возвращает Promise. Если возвращаемое значение не является Promise, оно автоматически оборачивается в Promise.

await-выражения

awaitможно использовать толькоasyncвнутри асинхронной функции. Он приостанавливает выполнение функции, ждёт разрешения Promise, затем продолжает выполнение и возвращает результат:

async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}

Обработка ошибок

подход try/catch

Обработкаasync/awaitНаиболее распространённый способ обработки ошибок — использоватьtry/catch:

Пример

async function getUser() {
  try {
    const response = await fetch('https://api.example.com/user');
    const user = await response.json();
    return user;
  } catch (error) {
    console.error('Error fetching user:', error);
    throw error; // При необходимости повторно выбросить ошибку
  }
}

Обработка Promise напрямую

Вы также можете напрямую обработать возвращённый Promise:

Пример

getUser()
  .then(user => console.log(user))
  .catch(error => console.error(error));

Практические примеры

Выполнение нескольких асинхронных операций параллельно

ИспользуйтеPromise.allwithasync/awaitчтобы выполнять несколько асинхронных операций параллельно:

Пример

async function fetchMultipleUrls(urls) {
  try {
    const requests = urls.map(url => fetch(url));
    const responses = await Promise.all(requests);
    const data = await Promise.all(responses.map(r => r.json()));
    return data;
  } catch (error) {
    console.error('Ошибка при получении данных:', error);
    throw error;
  }
}

Пример операции с базой данных

Пример

async function getUserAndPosts(userId) {
  try {
    const user = await User.findById(userId);
    const posts = await Post.find({ userId });
    return { user, posts };
  } catch (error) {
    console.error('Database error:', error);
    throw error;
  }
}

Лучшие практики

  1. Всегда обрабатывайте ошибки: Не игнорируйтеawaitошибки, которые могут быть выброшены; используйтеtry/catchили.catch()для обработки
  2. Избегайте ненужного await: Если вам не нужно ждать результата, вы можете вернуть Promise напрямую
  3. Используйте параллелизм разумно: Несколько независимых асинхронных операций должны выполняться параллельно (используйтеPromise.all)
  4. Поддерживайте код понятным: Избегайте чрезмерно глубокойasync/awaitвложенности; выделяйте функции при необходимости
  5. Следите за влиянием на производительность: Каждыйawaitприостанавливает выполнение функции; обращайте особое внимание в циклах

Часто задаваемые вопросы

Связь между async/await и Promise

async/await— это синтаксический сахар, построенный поверх Promise. Любаяasync-функция возвращает Promise, и любойawaitможет стоять перед Promise.

Почему моя async-функция возвращает undefined?

Возможно, это потому, что вы забыли использоватьawaitbeforereturn, или функция завершается до того, как Promise разрешится.

Можно ли использовать await на верхнем уровне?

В ES-модулях (файлах с расширением.mjsилиpackage.jsonСредняя"type": "module"), можно использоватьawaitнапрямую на верхнем уровне. В модулях CommonJS его нужно обернуть вasyncфункцию.

Пример

// В ES-модулях
const data = await fetchData();
console.log(data);
Другие расширения