Что они делают и когда какие использовать?

Введение

Асинхронное программирование стало фундаментальным аспектом современной веб-разработки, особенно в JavaScript.

Введение промисов в ES6 и недавнее введение синтаксиса Async/Await в ES8 значительно изменили способ написания асинхронного кода разработчиками.

В этой статье мы подробно сравним Async/Await и Promises в JavaScript. Мы объясним, что они собой представляют, как они работают, их сходства и различия, и когда использовать один над другим. Кроме того, мы предоставим пример кода для каждого случая.

Понимание асинхронного программирования

Чтобы понять Async/Await и Promises, мы должны сначала понять концепцию асинхронного программирования. Синхронное программирование предполагает последовательное выполнение кода, когда каждая строка кода выполняется одна за другой.

Однако в контексте веб-разработки выполнение многих задач, таких как сетевые запросы или запросы к базе данных, занимает много времени. Эти задачи могут привести к зависанию или зависанию приложения, что делает невозможным выполнение любого другого кода, пока задача не будет завершена.

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

Это достигается за счет использования неблокирующих операций, когда функция вызывается, а затем немедленно возвращается, позволяя программе продолжать выполнение, пока функция выполняет свою задачу в фоновом режиме. Как только функция завершается, она уведомляет программу через функцию обратного вызова или промис.

Что такое обещания?

Промисы — это языковая функция, представленная в ES6 для упрощения асинхронного программирования в JavaScript.

Обещания представляют собой значение, которое может быть еще недоступно, но будет разрешено в какой-то момент в будущем. Обещание может иметь одно из трех состояний: ожидание, выполнение или отклонение.

  • Ожидание: начальное состояние промиса при его создании.
  • Выполнено: обещание успешно разрешено, и значение доступно.
  • Отклонено: Обещание было отклонено, и доступно сообщение об ошибке.

Промисы имеют два основных метода: then() и catch(). Метод then() вызывается при успешном разрешении промиса, а метод catch() вызывается при отклонении промиса.

Вот пример использования Promise для получения данных с удаленного сервера с помощью метода fetch():

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

В этом примере мы используем метод fetch() для получения данных с удаленного сервера. Метод then() вызывается дважды: один раз для синтаксического анализа тела ответа в формате JSON и один раз для вывода данных на консоль. Метод catch() вызывается, если во время операции fetch() возникает ошибка.

Что такое асинхронное/ожидание?

Async/Await — это языковая функция, представленная в ES8, которая еще больше упрощает асинхронное программирование, позволяя разработчикам писать асинхронный код, который выглядит синхронно.

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

Асинхронные функции возвращают обещание, которое разрешается с возвращаемым значением функции или отклоняется с ошибкой, если таковая возникает. Ключевое слово Async используется для объявления функции как асинхронной, а ключевое слово Await используется для ожидания разрешения промиса перед продолжением выполнения.

Вот пример использования Async/Await для получения данных с удаленного сервера с помощью метода fetch():

async function fetchData() {
  try {
    const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}

В этом примере мы используем ключевое слово async для объявления функции fetchData() как асинхронной. Затем мы используем блок try-catch для обработки ошибок, которые могут возникнуть во время выполнения функции.

Внутри блока try мы используем ключевое слово await для ожидания разрешения метода fetch() перед продолжением выполнения. Затем мы используем метод response.json() для синтаксического анализа тела ответа в формате JSON и регистрации полученных данных в консоли.

Сходства и различия

Promises и Async/Await имеют много общего. Оба являются неблокирующими, что означает, что они позволяют программе продолжать выполнение, ожидая завершения задачи. Оба также предоставляют способ обработки ошибок, которые могут возникнуть во время выполнения асинхронной задачи.

Основное различие между Promises и Async/Await заключается в синтаксисе, используемом для написания асинхронного кода. Обещания используют цепочки then() и catch() для обработки разрешенных и отклоненных состояний соответственно.

Напротив, Async/Await использует блок try-catch для обработки ошибок и ключевое слово await для ожидания разрешения промиса перед продолжением выполнения.

Когда использовать обещания

Промисы — хороший выбор, когда вам нужно выполнить последовательность асинхронных операций, где каждая операция зависит от предыдущей.

Промисы также предоставляют способ одновременной обработки нескольких асинхронных операций, что может повысить производительность за счет параллельного выполнения задач.

Вот пример использования промисов для выполнения последовательности асинхронных операций:

function getTodoById(id) {
  return fetch(`https://jsonplaceholder.typicode.com/todos/${id}`)
    .then(response => response.json())
    .then(todo => {
      return fetch(`https://jsonplaceholder.typicode.com/users/${todo.userId}`)
        .then(response => response.json())
        .then(user => {
          todo.username = user.username;
          return todo;
        });
    });
}

В этом примере мы используем два метода fetch() для получения данных с удаленного сервера. Мы используем промисы для выполнения последовательности операций, где мы сначала извлекаем элемент задачи, затем извлекаем пользователя, связанного с элементом задачи, и, наконец, добавляем свойство имени пользователя в элемент задачи.

Когда использовать Async/Await

Async/Await — хороший выбор, когда вам нужно написать асинхронный код, который выглядит синхронно, что облегчает его чтение и понимание.

Async/Await также может упростить обработку ошибок, так как позволяет вам использовать блок try-catch для обработки ошибок вместо использования метода catch() промиса.

Вот пример использования Async/Await для выполнения той же последовательности асинхронных операций, что и в предыдущем примере:

async function getTodoById(id) {
  try {
    const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${id}`);
    const todo = await response.json();
    const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${todo.userId}`);
    const user = await userResponse.json();
    todo.username = user.username;
    return todo;
  } catch (error) {
    console.error(error);
  }
}

В этом примере мы используем Async/Await для выполнения той же последовательности операций, что и в предыдущем примере. Код стал более лаконичным и его легче читать, так как мы используем ключевое слово await для ожидания разрешения каждого промиса перед продолжением выполнения.

Заключение

Асинхронное программирование — важный аспект современной веб-разработки, а Promises и Async/Await — ценные инструменты для написания асинхронного кода на JavaScript.

Обещания — хороший выбор, когда вам нужно выполнить последовательность асинхронных операций или одновременно обрабатывать несколько асинхронных операций.

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

Важно отметить, что Promises и Async/Await не исключают друг друга и во многих случаях могут использоваться вместе. Например, вы можете использовать Promises для выполнения последовательности операций, а затем использовать Async/Await для ожидания завершения этих операций перед продолжением выполнения.

В общем, рекомендуется использовать Async/Await, когда это возможно, так как это может упростить обработку ошибок и сделать ваш код более читабельным. Тем не менее, промисы по-прежнему являются ценным инструментом, особенно когда вам нужно одновременно обрабатывать несколько асинхронных операций.

В заключение отметим, что и Promises, и Async/Await являются мощными инструментами для написания асинхронного кода на JavaScript. Понимание их сходств и различий, а также того, когда лучше использовать одно, может помочь вам писать более эффективный и читаемый код.