Какие знаешь утилиты Promise кроме Promise.all?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Утилиты Promise кроме Promise.all
В JavaScript есть много встроенных и полезных утилит для работы с Promise. Рассмотрим основные и их применение.
Встроенные утилиты Promise
1. Promise.race()
Возвращает результат первого решённого Promise:
// Пример 1: Таймаут запроса
function fetchWithTimeout(url, timeout = 5000) {
return Promise.race([
fetch(url),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
),
]);
}
fetchWithTimeout('https://api.example.com/data')
.then(response => response.json())
.catch(error => console.log(error.message)); // Timeout после 5 сек
// Пример 2: Первый ответивший сервер
const servers = [
'https://api1.example.com',
'https://api2.example.com',
'https://api3.example.com',
];
const firstResponse = Promise.race(
servers.map(server => fetch(server))
);
firstResponse.then(response => {
console.log('Got response from fastest server');
});
// Пример 3: Отмена операции по timeout
const operation = Promise.race([
doLongOperation(),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Cancelled')), 10000)
),
]);
2. Promise.allSettled()
Ожидает все Promise и возвращает результаты (успех или ошибка):
// Promise.allSettled НЕ отклоняется, даже если один Promise отклонится
const promises = [
Promise.resolve(1),
Promise.reject(new Error('Error')),
Promise.resolve(3),
];
Promise.allSettled(promises).then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: Error('Error') },
// { status: 'fulfilled', value: 3 }
// ]
});
// Практический пример: загрузка нескольких ресурсов
const userIds = [1, 2, 3, 4, 5];
const promises = userIds.map(id =>
fetch(`/api/users/${id}`)
.then(r => r.json())
.catch(e => ({ error: e.message, userId: id }))
);
Promise.allSettled(promises).then(results => {
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
console.log('Loaded:', successful.length);
console.log('Failed:', failed.length);
});
3. Promise.any()
Возвращает первый успешно решённый Promise. Если все отклонены, выбрасывает ошибку:
// Получаем первый успешный запрос
const servers = [
'https://api1.example.com/data',
'https://api2.example.com/data',
'https://api3.example.com/data',
];
Promise.any(servers.map(url => fetch(url)))
.then(response => response.json())
.then(data => console.log('Got data:', data))
.catch(error => console.log('All servers failed:', error));
// Практический пример: подключение к нескольким сервисам
const connectToService = (service) => {
return new Promise((resolve, reject) => {
const timeout = setTimeout(
() => reject(new Error(`${service} timeout`)),
2000
);
performConnection(service)
.then(result => {
clearTimeout(timeout);
resolve(result);
})
.catch(error => {
clearTimeout(timeout);
reject(error);
});
});
};
Promise.any([
connectToService('redis'),
connectToService('memcache'),
connectToService('mongodb'),
])
.then(connection => console.log('Connected'))
.catch(error => console.log('All services down:', error));
Встроенные методы Promise
4. Promise.resolve()
Создаёт уже решённый Promise:
// Обычное использование
Promise.resolve(42).then(value => console.log(value)); // 42
// С thenable объектом
const thenable = {
then(resolve) {
resolve('Custom thenable');
},
};
Promise.resolve(thenable).then(value => console.log(value));
// Практический пример: унификация асинхронного кода
function getData(source) {
if (source instanceof Promise) {
return source;
}
if (typeof source === 'function') {
return Promise.resolve(source());
}
return Promise.resolve(source);
}
getData(42).then(console.log); // 42
getData(() => 42).then(console.log); // 42
getData(Promise.resolve(42)).then(console.log); // 42
5. Promise.reject()
Создаёт отклонённый Promise:
Promise.reject(new Error('Something went wrong'))
.catch(error => console.log(error.message));
// Практический пример: валидация
function validateUser(user) {
if (!user.email) {
return Promise.reject(new Error('Email is required'));
}
return Promise.resolve(user);
}
validateUser({}).catch(error => console.log(error.message));
Полезные паттерны и комбинации
Пример 1: Promise.all с обработкой ошибок
// ❌ Promise.all отклоняется при первой ошибке
Promise.all([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments'),
])
.catch(error => console.log('One failed:', error));
// ✅ Promise.allSettled продолжает загружать
Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments'),
])
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Request ${index} succeeded`);
} else {
console.log(`Request ${index} failed:`, result.reason);
}
});
});
Пример 2: Композиция Promise
// Запустить параллельно, потом последовательно
Promise.all([
fetch('/api/user'),
fetch('/api/settings'),
])
.then(responses => Promise.all(responses.map(r => r.json())))
.then(([user, settings]) => {
console.log('User:', user);
console.log('Settings:', settings);
});
Пример 3: Retry с Promise.race
function retryWithTimeout(fn, retries = 3, timeout = 5000) {
const attempt = () => {
return Promise.race([
fn(),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Timeout')), timeout)
),
]);
};
return attempt().catch(error => {
if (retries <= 0) throw error;
return retryWithTimeout(fn, retries - 1, timeout);
});
}
retryWithTimeout(
() => fetch('/api/unstable'),
3,
5000
).then(response => response.json());
Пример 4: Чейн с обработкой ошибок
fetch('/api/user')
.then(r => r.json())
.then(user => fetch(`/api/user/${user.id}/posts`))
.then(r => r.json())
.then(posts => {
console.log('User posts:', posts);
})
.catch(error => {
// Ловит ошибку из любого шага
console.log('Error:', error);
});
Таблица сравнения
| Метод | Возвращает | При ошибке | Когда использовать |
|---|---|---|---|
| all() | Массив результатов | Отклоняется | Все успешные |
| allSettled() | Массив результатов/ошибок | Никогда | Все равно результаты |
| race() | Первый результат | Отклоняется | Первый готов |
| any() | Первый успешный | Отклоняется | Первый успешный |
| resolve() | Решённый Promise | - | Унификация |
| reject() | Отклонённый Promise | - | Явная ошибка |
Практические советы
-
Используй Promise.allSettled() для независимых операций, где ошибка в одной не блокирует остальные
-
Используй Promise.race() для таймаутов — это идеальное применение
-
Используй Promise.any() для redundancy — когда нужна хотя бы одна успешная операция
-
Комбинируй методы — Promise.all + Promise.allSettled часто используются вместе
-
Помни про обработку ошибок — всегда добавляй .catch() в цепь промисов