Оволодіння методами Promise в JavaScript: всеосяжний посібник

Впровадження методів Promise в JS

pic

Привіт, прекрасні люди в Інтернеті.

API Promise в JavaScript є основою для роботи з асинхронним кодом. Його корисність проявляється в таких методах, як Promise.all, Promise.allSettled, Promise.any і Promise.race. Кожен метод вирішує конкретні сценарії, що робить асинхронне програмування зручнішим і виразнішим. У цій статті ми розглянемо їх реалізацію, варіанти використання та особливі випадки.

Promise.all

Огляд

Promise.all виконується, коли всі обіцянки в масиві будуть виконані.
Впровадження методів Promise в JS

Якщо будь-яка обіцянка відхилена, весь метод буде негайно відхилений.

Кастомна реалізація

PromiseAll = function(promises) {  
 const result = []; // Для зберігання значень, отриманих від обіцянок  
 let totalResolved = 0; // Для відслідковування кількості виконаних обіцянок  
 return new Promise((resolve, reject) => {  
 // Якщо вхідний масив порожній, одразу вирішуємо з порожнім масивом  
 if (promises.length === 0) return resolve(result);  
 // Проходимо по кожній обіцянці в масиві  
 promises.forEach((promise, index) => {  
 // Переконуємося, що поточне значення обробляється як обіцянка  
 Promise.resolve(promise).then(res => {  
 result[index] = res; // Зберігаємо значення обіцянки на відповідному індексі  
 totalResolved++; // Збільшуємо лічильник виконаних обіцянок  
 // Якщо всі обіцянки виконані, вирішуємо основну обіцянку з результатами  
 if (totalResolved === promises.length) {  
 return resolve(result);  
 }  
 }).catch(err => {  
 // Якщо будь-яка обіцянка відхилена, відхиляємо основну обіцянку негайно  
 return reject(err);  
 });  
 });  
 });  
};

Приклад використання

const promise1 = Promise.resolve('A');  
const promise2 = Promise.resolve('B');  
const promise3 = Promise.reject('C');  

PromiseAll([promise1, promise2, promise3]).then(res => {  
 console.log(res);  
}).catch(err => {  
 console.error(err); // Виводить 'C'  
});

Граничні випадки

  • Порожній масив: вирішується в порожній масив.
  • Значення, що не є обіцянками (наприклад, undefined, null): автоматично вирішуються.
PromiseAll([undefined, null, 'Static value']).then(res => {  
 console.log(res); // Виводить [undefined, null, "Static value"]  
});

Promise.allSettled

Огляд

Promise.allSettled чекає, поки всі обіцянки не завершаться, незалежно від того, чи були вони виконані чи відхилені.

Кастомна реалізація

PromiseAllSettled = function(promises) {  
 const result = []; // Для зберігання результатів кожної обіцянки  
 let totalResolved = 0; // Для відслідковування кількості завершених обіцянок  
 return new Promise(resolve => {  
 // Якщо вхідний масив порожній, одразу вирішуємо з порожнім масивом  
 if (promises.length === 0) return resolve(result);  
 // Проходимо по кожній обіцянці в масиві  
 promises.forEach((promise, index) => {  
 // Переконуємося, що поточне значення обробляється як обіцянка  
 Promise.resolve(promise).then(res => {  
 // Якщо обіцянка виконана, зберігаємо її значення і статус  
 result[index] = { status: 'fulfilled', value: res };  
 }).catch(err => {  
 // Якщо обіцянка відхилена, зберігаємо її причину і статус  
 result[index] = { status: 'rejected', reason: err };  
 }).finally(() => {  
 // Збільшуємо лічильник завершених обіцянок  
 totalResolved++;  
 // Якщо всі обіцянки завершилися, вирішуємо основну обіцянку з результатами  
 if (totalResolved === promises.length) {  
 return resolve(result);  
 }  
 });  
 });  
 });  
};

Приклад використання

PromiseAllSettled([promise1, promise2, promise3]).then(res => {  
 console.log(res);  
});

Вивід:

[  
 { status: 'fulfilled', value: 'A' },  
 { status: 'fulfilled', value: 'B' },  
 { status: 'rejected', reason: 'C' }  
]

Граничні випадки

  • Порожній масив: вирішується в порожній масив.
  • Значення, що не є обіцянками (наприклад, undefined, null): автоматично вирішуються.
PromiseAllSettled([42, "hello", undefined, null]).then(results => {  
 console.log(results);  
});

Вивід

[  
 { status: 'fulfilled', value: 42 },  
 { status: 'fulfilled', value: 'hello' },  
 { status: 'fulfilled', value: undefined },  
 { status: 'fulfilled', value: null }  
]

Promise.any

Огляд

Promise.any вирішується першою виконаною обіцянкою.
Якщо всі обіцянки відхилені, кидається помилка AggregateError.

Кастомна реалізація

PromiseAny = function(promises) {  
 const errors = []; // Для зберігання помилок від відхилених обіцянок  
 let totalRejected = 0; // Для відслідковування кількості відхилених обіцянок  
 return new Promise((resolve, reject) => {  
 // Якщо вхідний масив порожній, відхиляємо з AggregateError одразу  
 if (promises.length === 0) return reject(new AggregateError(errors, "Empty array"));  
 // Проходимо по кожній обіцянці в масиві  
 promises.forEach((promise, index) => {  
 // Переконуємося, що поточне значення обробляється як обіцянка  
 Promise.resolve(promise).then(res => {  
 // Якщо обіцянка виконана, вирішуємо основну обіцянку негайно  
 return resolve(res);  
 }).catch(err => {  
 // Зберігаємо помилку від відхиленої обіцянки  
 totalRejected++;  
 errors[index] = err;  
 // Якщо всі обіцянки відхилені, відхиляємо з AggregateError  
 if (totalRejected === promises.length) {  
 return reject(new AggregateError(errors, "All promises were rejected"));  
 }  
 });  
 });  
 });  
};

Приклад використання

PromiseAny([promise1, promise2, promise3]).then(res => {  
 console.log(res); // Виводить 'B'  
}).catch(err => {  
 console.error(err); // Якщо всі обіцянки відхилені  
});

Граничні випадки

  • Порожній масив: кидає AggregateError.

Promise.race

Огляд

Promise.race вирішується або відхиляється, як тільки перша обіцянка завершується.

Кастомна реалізація

PromiseRace = function(promises) {  
 return new Promise((resolve, reject) => {  
 // Якщо вхідний масив порожній, вирішуємо негайно  
 if (promises.length === 0) return resolve();  
 // Проходимо по кожній обіцянці в масиві  
 promises.forEach(promise => {  
 // Переконуємося, що поточне значення обробляється як обіцянка  
 Promise.resolve(promise).then(res => {  
 // Вирішуємо основну обіцянку, як тільки перша обіцянка буде виконана  
 return resolve(res);  
 }).catch(err => {  
 // Відхиляємо основну обіцянку, як тільки перша обіцянка буде відхилена  
 return reject(err);  
 });  
 });  
 });  
};

Приклад використання

PromiseRace([promise1, promise2]).then(res => {  
 console.log(res); // Виводить 'Promise2 resolved' після 2000мс  
}).catch(err => {  
 console.error(err); // Якщо швидша обіцянка відхилена  
});

Граничні випадки

  • Порожній масив: вирішується негайно.
  • Значення, що не є обіцянками, обробляються як виконані негайно.
PromiseRace([null, undefined]).then(res => {  
 console.log(res); // Виводить 'null'  
});

Висновок

Ці методи пропонують гнучкість для різних асинхронних сценаріїв. Обробляючи граничні випадки, такі як порожні масиви та значення, що не є обіцянками, ми забезпечуємо надійні реалізації, придатні для реальних застосувань.

Я завжди прагну до вдосконалення і буду радий почути ваші думки! Якщо у вас є пропозиції, відгуки або теми, які ви хотіли б, щоб я розглянув, не соромтесь поділитися ними в коментарях нижче. Ваші зауваження дуже цінні! 🙂

Перекладено з: Mastering Promise Methods in JavaScript: A Comprehensive Guide

Leave a Reply

Your email address will not be published. Required fields are marked *