Promise в JavaScript: Асинхронность и примеры

Асинхронность с использованием callback-функций

Рассмотрим асинхронный запрос на сервер с использованием callback-функций:

console.log('request data'); // Симулируем отправку запроса
setTimeout(() => {
  console.log('preparing data'); // Сервер готовит данные (2 секунды)
  const backendData = { server: 'localhost', port: 2000, status: 'working' };
  setTimeout(() => {
    console.log('data received');
    backendData.modified = true; // Модифицируем данные
    console.log(backendData); // Выводим полученные данные
  }, 2000); // Отправка данных клиенту (2 секунды)
}, 2000);

Такой подход приводит к вложенности callback-функций. При увеличении количества асинхронных операций код становится сложным в поддержке и чтении.

Promise: решение проблемы вложенности

Promise решает проблему вложенности callback-функций при работе с асинхронными операциями.

Пример создания Promise:

const p = new Promise((resolve, reject) => {
  console.log('request data');
  setTimeout(() => {
    const backendData = { server: 'localhost', port: 2000, status: 'working' };
    resolve(backendData); // Вызываем resolve при успешном завершении
  }, 2000);
});

resolve – функция, вызываемая при успешном завершении асинхронной операции. Она принимает данные для дальнейшей передачи.

Для обработки данных используется метод .then():

p.then((data) => {
  console.log('promise resolve');
  console.log(data); // Выводим данные
});

Метод .then() принимает callback-функцию, вызываемую после успешного выполнения Promise.

Более сложный пример с Promise

Добавим ещё одну асинхронную операцию:

const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    data.modified = true;
    resolve(data);
  }, 2000);
});

p.then((data) => {
  return p2; // Возвращаем новый Promise
}).then((clientData) => {
  console.log('data received');
  console.log(clientData);
});

Возвращение нового Promise из первого .then() позволяет избежать вложенности и улучшает читаемость кода.

Цепочки Promise (Chaining)

Возвращение Promise из .then() позволяет создавать цепочки Promise, упрощая работу с последовательными асинхронными операциями. Вместо вложенных .then(), используется одна цепочка.

Обработка ошибок с помощью .catch()

Для обработки ошибок используется метод .catch():

p.then((data) => {
    // ...
}).catch((error) => {
  console.error('Error:', error);
});

Метод .catch() принимает callback-функцию, вызываемую при ошибке в цепочке Promise.

Метод .finally()

Метод .finally() выполняется всегда, независимо от результата выполнения Promise:

p.then((data) => {
    // ...
}).catch((error) => {
  console.error('Error:', error);
}).finally(() => {
  console.log('finally');
});

Утилита для задержки sleep()

Функция sleep(), создающая Promise с задержкой:

const sleep = (ms) => {
  return new Promise(resolve => setTimeout(resolve, ms));
};

Использование:

sleep(2000).then(() => console.log('2 seconds'));
sleep(3000).then(() => console.log('3 seconds'));

Promise.all() и Promise.race()

Promise.all() ожидает выполнения всех переданных Promise:

Promise.all([sleep(2000), sleep(3000)]).then(() => console.log('all promises resolved'));

Promise.race() возвращает результат первого выполненного Promise:

Promise.race([sleep(2000), sleep(3000)]).then(() => console.log('first promise resolved'));

Заключение

Promise обеспечивает удобный и элегантный способ работы с асинхронными операциями в JavaScript, избегая проблемы callback hell и повышая читаемость кода. Использование цепочек Promise, методов .catch() и .finally(), а также Promise.all() и Promise.race() позволяет создавать эффективный и надежный асинхронный код.

Что будем искать? Например,программа