then/catch/finally: цепочки промисов
Как работают цепочки промисов? 🔗
Представьте, что вы шеф-повар, который готовит сложное блюдо по шагам. Каждый шаг зависит от предыдущего — нельзя нарезать овощи, пока их не купили, и нельзя подавать блюдо, пока оно не приготовлено. Вот так же работают цепочки промисов в JavaScript!
// Простая цепочка промисов
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => processData(data))
.catch(error => console.error('Ошибка:', error))
.finally(() => console.log('Запрос завершён'))
then() — ваш верный помощник ⛓️
Метод then() — это фундамент цепочек. Он принимает два аргумента (хотя второй необязателен):
- Функция, которая выполнится при успешном выполнении промиса
- Функция для обработки ошибок (но лучше использовать
catch)
// Практический пример с then()
function getUser(id) {
return fetch(`/api/users/${id}`)
.then(response => {
if (!response.ok) throw new Error('Ошибка сети')
return response.json()
})
.then(user => {
console.log('Пользователь получен:', user)
return user
})
}
💡 Важно: каждый
then()возвращает новый промис, поэтому цепочки можно продолжать бесконечно!
catch() — спасательный круг 🛟
Когда в цепочке происходит ошибка, JavaScript ищет ближайший catch(). Это как аварийный выход — можно либо обработать ошибку, либо продолжить цепочку с новым значением.
// Обработка ошибок с style
fetch('/api/orders/123')
.then(response => response.json())
.then(order => {
if (!order.valid) throw new Error('Недействительный заказ')
return processOrder(order)
})
.catch(error => {
console.error('Ошибка заказа:', error.message)
return getDefaultOrder() // Продолжаем цепочку с запасным вариантом
})
.then(finalOrder => {
// Сюда попадём в любом случае — с обработанной ошибкой или без
displayOrder(finalOrder)
})
finally() — финальный аккорд 🎹
finally() выполнится в любом случае — был ли промис успешным или завершился с ошибкой. Идеально для очистки ресурсов или скрытия лоадеров.
let isLoading = true
fetch('/api/products')
.then(response => response.json())
.then(products => renderProducts(products))
.catch(error => showError(error))
.finally(() => {
isLoading = false
console.log('Загрузка завершена')
})
🔥 Интересный факт:
finally()не получает аргументов и не влияет на возвращаемое значение цепочки.
Комбинируем всё вместе 🧩
Давайте соберём полноценный пример, имитирующий реальный сценарий:
// Загрузка пользовательских данных с обработкой всех случаев
function loadUserProfile(userId) {
let loading = true
let profile = null
fetch(`/api/users/${userId}`)
.then(response => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`)
return response.json()
})
.then(userData => {
profile = transformUserData(userData)
return fetch(`/api/users/${userId}/friends`)
})
.then(friendsResponse => friendsResponse.json())
.then(friends => {
profile.friends = friends
return profile
})
.catch(error => {
console.error('Ошибка загрузки:', error)
return getCachedProfile(userId) // Пробуем запасной вариант
})
.finally(() => {
loading = false
document.querySelector('#loader').style.display = 'none'
})
.then(finalProfile => {
renderUserProfile(finalProfile)
})
}
Ловушки и лучшие практики 🚨
- Не забывайте возвращать значения из
then()— иначе следующийthen()получитundefined - Всегда обрабатывайте ошибки — не оставляйте "висячих" промисов
- Избегайте "ада колбэков" — не вкладывайте
then()друг в друга - Именуйте функции-обработчики — так проще отлаживать код
Плохой пример ❌:
fetch('/api/data').then(result => {
result.json().then(data => {
process(data).then(() => {
console.log('Готово!')
})
})
})
Хороший пример ✅:
fetch('/api/data')
.then(response => response.json())
.then(processData)
.then(() => console.log('Готово!'))
.catch(handleError)
Когда цепочки — идеальное решение? ✨
Цепочки промисов особенно хороши для:
- Последовательных асинхронных операций
- Обработки данных поэтапно
- Сложной логики обработки ошибок
- Сценариев, где нужно гарантированно выполнить финальный код
Помните: современный JavaScript предлагает и async/await, но понимание цепочек промисов — это фундамент, без которого не стать настоящим асинхронным ниндзя! 🏼