Что такое Promise в JavaScript/Node.js?

Ответ

Promise (Обещание) — это объект в JavaScript, представляющий результат (успешный или неудачный) асинхронной операции, которая завершится в будущем. Он является фундаментальной частью работы с асинхронностью в Node.js.

Состояния Promise:

  • pending (ожидание): Начальное состояние, операция еще не завершена.
  • fulfilled (выполнено): Операция завершилась успешно. Promise переходит в это состояние при вызове resolve(value).
  • rejected (отклонено): Операция завершилась с ошибкой. Promise переходит в это состояние при вызове reject(error).

Пример создания и использования:

const readFileAsync = (filename) => {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, 'utf8', (err, data) => {
            if (err) {
                reject(new Error(`Failed to read file: ${err.message}`));
            } else {
                resolve(data);
            }
        });
    });
};

// Использование с цепочкой .then() и .catch()
readFileAsync('config.json')
    .then(data => {
        console.log('File content:', data);
        return JSON.parse(data);
    })
    .then(config => console.log('DB Host:', config.dbHost))
    .catch(error => console.error('Error:', error.message));

Ключевые преимущества для Node.js:

  • Избегание "Callback Hell": Позволяет структурировать асинхронный код более линейно и читаемо.
  • Цепочки вызовов: Методы .then() всегда возвращают новый Promise, что позволяет строить последовательности асинхронных операций.
  • Централизованная обработка ошибок: Все ошибки в цепочке можно перехватить одним блоком .catch() в конце.
  • Интеграция с async/await: Promise — основа для синтаксиса async/await, который делает асинхронный код похожим на синхронный.

Статические методы для работы с коллекциями Promise:

  • Promise.all([p1, p2]): Ждет выполнения всех промисов. Если один отклоняется — вся операция отклоняется.
  • Promise.allSettled([p1, p2]): Ждет завершения всех промисов (успех или ошибка) и возвращает массив с результатами каждого.
  • Promise.race([p1, p2]): Возвращает результат первого завершившегося промиса (fulfilled или rejected).

Ответ 18+ 🔞

Слушай, давай разберем эту тему без соплей, как есть. Promise (Обещание) — это такая хитрая жопа в JavaScript, которая говорит: «Мужик, я ща тут асинхронную операцию делаю, погоди чутка, потом скажу — получилось или всё накрылось медным тазом». В Node.js без этого нихуя не работает, потому что всё там асинхронное, как очередь в поликлинике.

Состояния у него, бля, всего три, проще некуда:

  • pending (ожидание): Ну тут всё ясно — сидит, грустит, ждёт-с. Операция ещё в процессе, как будто вода в чайнике греется.
  • fulfilled (выполнено): Всё, красава! Задача сделана, Promise вызвал resolve(value) и с чувством выполненного долга отдаёт результат. Успех, ёпта!
  • rejected (отклонено): Ну тут, ясень пень, пиздец. Что-то пошло не так, вызвали reject(error), и теперь вместо данных у тебя ошибка, с которой надо разбираться.

Вот смотри, как это в коде выглядит, на реальном примере:

const readFileAsync = (filename) => {
    return new Promise((resolve, reject) => {
        fs.readFile(filename, 'utf8', (err, data) => {
            if (err) {
                reject(new Error(`Failed to read file: ${err.message}`));
            } else {
                resolve(data);
            }
        });
    });
};

// А вот как этим пользоваться, без этих ваших callback hell
readFileAsync('config.json')
    .then(data => {
        console.log('File content:', data);
        return JSON.parse(data);
    })
    .then(config => console.log('DB Host:', config.dbHost))
    .catch(error => console.error('Error:', error.message));

А теперь, почему это вообще охуенно для Node.js:

  • Пиздец какая вложенность колбэков больше не нужна. Раньше код был как матрёшка — колбэк в колбэке, в колбэке, в колбэке. С промисами всё ровно и последовательно, .then за .then.
  • Цепочки — это сила. Каждый .then() возвращает новый Promise, так что можно строить целые конвейеры из операций. Сделал одно — передал дальше.
  • Ошибки ловишь в одном месте. Не нужно в каждом колбэке проверять if (err). Кинул один .catch() в конце цепочки — и он перехватит всё, что по дороге пошло не так. Доверия ебать ноль к этим ошибкам, но хоть управлять можно.
  • Это же основа для async/await! Вся эта магия, когда асинхронный код выглядит как обычный, построена на промисах. Без них async/await — просто слова.

Ещё есть статические методы, когда нужно работать с кучей промисов сразу:

  • Promise.all([p1, p2]): Ждёт, пока все обещания выполнятся. Но если хоть один сдохнет — то и весь Promise.all сразу летит в rejected. Жестко, но справедливо.
  • `Promise.allSettled([p1, p2])**: А вот это по-русски: «Мне похуй, как ты завершишься, главное — завершись». Ждёт все, и успешные, и провальные, и потом отдаёт массив с результатами по каждому. Удобно, когда нужно просто узнать итог по всем.
  • Promise.race([p1, p2]): Гонки, сука! Кто первый финишировал (неважно, успехом или ошибкой), того результат и получаешь. Остальные уже неинтересны.

Видео-ответы