Promise
Promise - це спеціальний об'єкт у JavaScript, який представляє результат асинхронної операції, що може завершитися пізніше, успішно або з помилкою. Простіше кажучи, Promise - це «обіцянка» дати результат у майбутньому: зараз відповіді немає, але вона буде, коли операція завершиться.
Теорія
TL;DR
- Promise представляє майбутній результат асинхронної операції.
- Стани:
pending, далі абоfulfilled, абоrejected; перехід відбувається лише один раз. resolve(value)переводить уfulfilled,reject(error)- уrejected.- Обробка результату:
.then(),.catch(),.finally(); кожен із них повертає новий Promise. - Комбінатори:
Promise.all(),Promise.allSettled(),Promise.race(). async/await- це синтаксичний цукор над Promise, а не окремий механізм.
Швидкий приклад
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Дані отримано!');
}, 2000);
});
}
fetchData().then((data) => console.log(data));fetchData() повертає Promise: через 2 секунди він резолвиться, і then() отримує результат.
Три стани Promise
| Стан | Опис | Приклад |
|---|---|---|
| pending | очікування, операція ще не завершена | запит у процесі |
| fulfilled | виконано успішно, є результат | дані отримано |
| rejected | відхилено, сталася помилка | сервер повернув 404 |
Створення Promise і обробка результату
Promise можна створити вручну:
const promise = new Promise((resolve, reject) => {
const success = Math.random() > 0.5;
if (success) {
resolve('Успіх!');
} else {
reject('Помилка!');
}
});resolve(value)переводить Promise у стан fulfilled;reject(error)переводить його у стан rejected.
Результат обробляють ланцюжком методів:
promise
.then((result) => {
console.log('Результат:', result);
})
.catch((error) => {
console.error('Помилка:', error);
})
.finally(() => {
console.log('Виконується завжди');
});| Метод | Коли викликається | Що повертає |
|---|---|---|
.then() | при успішному виконанні (resolve) | новий Promise |
.catch() | при помилці (reject) | новий Promise |
.finally() | у будь-якому разі (успіх або помилка) | новий Promise |
Приклад із помилкою:
function fetchUser() {
return new Promise((_, reject) => {
setTimeout(() => reject('Користувача не знайдено'), 1000);
});
}
fetchUser()
.then(user => console.log(user))
.catch(err => console.error(err));Вивід:
Користувача не знайденоЛанцюжки Promise (promise chaining)
Кожен .then() повертає новий Promise, тому асинхронні дії можна вишиковувати в ланцюжок:
getUser()
.then(user => getPosts(user.id))
.then(posts => getComments(posts[0].id))
.then(comments => console.log(comments))
.catch(err => console.error('Помилка:', err));Перевага: немає вкладеності, код читається згори вниз, на відміну від callback hell.
Для вже готового значення є скорочена форма:
Promise.resolve('OK').then(console.log); // "OK"
Promise.reject('Помилка').catch(console.error); // "Помилка"Паралельні Promise
Promise.all() чекає, поки виконаються всі
Promise.all([
fetch('/user'),
fetch('/posts'),
]).then(([userRes, postRes]) => {
console.log('Обидві відповіді отримано');
});Якщо хоча б один Promise завершиться з помилкою, увесь all() буде rejected.
Promise.allSettled() чекає всі, незалежно від помилок
Promise.allSettled([
fetch('/user'),
fetch('/wrong-url'),
]).then(console.log);Результат:
[
{ status: "fulfilled", value: Response },
{ status: "rejected", reason: TypeError }
]Promise.race() повертає перший, що завершився
Promise.race([
fetch('/slow'),
fetch('/fast'),
]).then(console.log);Promise і async/await
Promise - це основа, на якій побудований синтаксис async/await:
async function main() {
try {
const user = await getUser();
const posts = await getPosts(user.id);
console.log(posts);
} catch (err) {
console.error(err);
}
}Тут await просто чекає на Promise, але робить код лінійним і зрозумілим.
Проста аналогія:
Promise схожий на доставку піци. Ви робите замовлення, і Promise створюється у стані
pending. Кур'єр везе замовлення, операція виконується. Кур'єр приїхав, Promise переходить уresolve. Кур'єр загубився, Promise переходить уreject. Ви можете «підписатися» на результат черезthenі обробити помилки черезcatch.
Підсумок
| Термін | Опис |
|---|---|
| Promise | Об'єкт, що представляє майбутній результат асинхронної операції |
| Стани | pending, далі fulfilled або rejected |
| Методи | .then(), .catch(), .finally() |
| Головна перевага | Спрощує роботу з асинхронністю, рятує від callback hell |
| Сучасний синтаксис | async/await побудований на Promise |
Типові помилки
- Думати, що Promise можна «перерезолвити»: після першого
resolveабоrejectстан фіксується назавжди, наступні виклики ігноруються. - Вважати, що Promise виконується ліниво. Функція-виконавець стартує одразу в момент
new Promise(...), ще до будь-якого.then(). - Забути
returnусередині.then(), через що наступна ланка отримуєundefinedзамість даних. - Ставити
.catch()не в кінці ланцюжка: тоді помилки з наступних.then()залишаться без обробки. - Брати
Promise.all()там, де потрібенPromise.allSettled(): одна помилка відкидає весь результат, хоча інші запити вже виконалися успішно. - Плутати
Promise.race()зPromise.any():raceповертає перший завершений результат, навіть якщо це помилка, аanyчекає на перший успішний. - Загортати в
new Promiseфункцію, яка вже повертає Promise: це зайвий рівень і джерело загублених помилок.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.