Промисы: основы
Promise — объект, представляющий результат асинхронной операции. Может быть в трёх состояниях: pending, fulfilled, rejected.
Состояния
- pending — операция выполняется
- fulfilled — успешно завершена, есть результат
- rejected — завершена с ошибкой
После перехода в fulfilled или rejected промис не меняется.
Создание
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('готово');
// или reject(new Error('ошибка'));
}, 1000);
});
resolve — успех, reject — ошибка. Вызывается только один раз.
then, catch, finally
promise
.then((value) => console.log(value))
.catch((error) => console.error(error))
.finally(() => console.log('завершено'));
then— на успехcatch— на ошибкуfinally— в любом случае
Цепочка
then возвращает новый промис. Можно строить цепочки:
fetch('/api/user')
.then((res) => res.json())
.then((user) => fetch(`/api/posts?userId=${user.id}`))
.then((res) => res.json())
.then((posts) => console.log(posts))
.catch((err) => console.error(err));
Каждый then получает результат предыдущего.
Возврат значения
Если then возвращает значение — оно попадёт в следующий then:
Promise.resolve(1)
.then((x) => x + 1)
.then((x) => x * 2)
.then((x) => console.log(x)); // 4
Если возвращает промис — цепочка ждёт его:
fetchUser()
.then((user) => fetchPosts(user.id))
.then((posts) => console.log(posts));
Обработка ошибок
Один catch ловит ошибки из всей цепочки:
fetchData()
.then((data) => process(data))
.then((result) => save(result))
.catch((err) => console.error('Где-то упало:', err));
Можно бросать ошибки вручную:
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
})
.catch((err) => console.error(err.message));
finally
Выполняется всегда:
showSpinner();
fetchData()
.then((data) => display(data))
.catch((err) => showError(err))
.finally(() => hideSpinner());
Promise.resolve и Promise.reject
Создание уже разрешённого промиса:
Promise.resolve(42).then((v) => console.log(v));
Promise.reject(new Error('fail')).catch((e) => console.error(e));
Промисы всегда асинхронны
Даже Promise.resolve выполняется после синхронного кода:
console.log('1');
Promise.resolve().then(() => console.log('2'));
console.log('3');
// 1, 3, 2
Вложенные промисы
Не пихай промис внутрь промиса:
// Плохо
fetchUser().then((user) => {
fetchPosts(user.id).then((posts) => {
console.log(posts);
});
});
// Хорошо
fetchUser()
.then((user) => fetchPosts(user.id))
.then((posts) => console.log(posts));
Вложенность теряет catch.
Итоги
- Промис — результат асинхронной операции
- Три состояния: pending, fulfilled, rejected
then,catch,finally- Цепочки через
then - Одна точка обработки ошибок на всю цепочку
- Промисы всегда асинхронны