Методы Promise .then(), .catch() и .finally() всегда возвращают новый Promise, что позволяет создавать цепочки асинхронных операций.
Понимание того, что возвращают методы .then(), .catch() и .finally(), критически важно для эффективной работы с цепочками Promise в JavaScript. Все три метода возвращают новые Promise, что делает возможным создание сложных асинхронных последовательностей.
Метод .then() принимает два необязательных параметра (обработчика) и всегда возвращает новый Promise:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('начальное значение'), 1000);
});
const newPromise = promise.then(
value => {
console.log(value); // 'начальное значение'
return 'новое значение';
},
error => {
console.error(error);
return 'значение при ошибке';
}
);
// newPromise - это новый Promise
newPromise.then(result => {
console.log(result); // 'новое значение'
});promise.then(value => {
return 'новая строка';
}).then(result => {
console.log(result); // 'новая строка'
});promise.then(value => {
return fetch('/api/data'); // Возвращает Promise
}).then(response => {
return response.json(); // Работаем с результатом fetch
}).then(data => {
console.log(data); // Данные из API
});promise.then(value => {
console.log(value);
// Неявно возвращает undefined
}).then(result => {
console.log(result); // undefined
});promise.then(value => {
throw new Error('Ошибка в обработчике');
}).catch(error => {
console.log(error.message); // 'Ошибка в обработчике'
});Метод .catch() также возвращает новый Promise и используется для обработки ошибок:
const errorPromise = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Ошибка')), 1000);
});
const newPromise = errorPromise.catch(error => {
console.log(error.message); // 'Ошибка'
return 'восстановленное значение';
});
newPromise.then(result => {
console.log(result); // 'восстановленное значение'
});fetch('/api/data')
.then(response => response.json())
.catch(error => {
console.error('Ошибка:', error);
return { error: true, data: [] }; // Восстановление после ошибки
})
.then(result => {
console.log(result); // { error: true, data: [] }
});promise.catch(error => {
console.error('Первичная обработка:', error);
throw error; // Повторный выброс
}).catch(error => {
console.error('Вторичная обработка:', error);
});Метод .finally() возвращает новый Promise, но с важной особенностью - он передает исходное значение Promise, независимо от возвращаемого значения обработчика:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('успешное значение'), 1000);
});
const newPromise = promise.finally(() => {
console.log('Очистка ресурсов');
return 'игнорируемое значение';
});
newPromise.then(result => {
console.log(result); // 'успешное значение' (не 'игнорируемое значение')
});Promise.resolve('данные')
.finally(() => {
console.log('Завершение');
return 'игнорируется';
})
.then(result => {
console.log(result); // 'данные'
});Promise.reject(new Error('ошибка'))
.finally(() => {
console.log('Завершение');
return 'игнорируется';
})
.catch(error => {
console.log(error.message); // 'ошибка'
});Понимание возвращаемых значений позволяет создавать сложные цепочки:
fetch('/api/user')
.then(response => {
if (!response.ok) throw new Error('Ошибка сети');
return response.json();
})
.then(user => {
console.log('Пользователь загружен:', user);
return fetch(`/api/profile/${user.id}`);
})
.then(response => response.json())
.then(profile => {
console.log('Профиль загружен:', profile);
return profile;
})
.catch(error => {
console.error('Ошибка в цепочке:', error);
return { error: true };
})
.finally(() => {
console.log('Запрос завершен');
});function loadUserData(userId) {
return fetch(`/api/users/${userId}`)
.then(response => {
if (!response.ok) throw new Error('Пользователь не найден');
return response.json();
})
.then(user => {
// Загружаем дополнительные данные
return Promise.all([
Promise.resolve(user),
fetch(`/api/posts/${userId}`).then(res => res.json()),
fetch(`/api/comments/${userId}`).then(res => res.json())
]);
})
.then(([user, posts, comments]) => {
return { user, posts, comments };
})
.catch(error => {
console.error('Ошибка загрузки:', error);
return null;
});
}fetch('/api/products')
.then(response => response.json())
.then(products => {
// Фильтрация данных
return products.filter(product => product.price > 0);
})
.then(filteredProducts => {
// Сортировка данных
return filteredProducts.sort((a, b) => b.price - a.price);
})
.then(sortedProducts => {
// Преобразование данных
return sortedProducts.map(product => ({
...product,
displayName: `${product.name} ($${product.price})`
}));
})
.then(finalProducts => {
console.log('Обработанные продукты:', finalProducts);
return finalProducts;
});// ❌ Неправильно - потеря значения в цепочке
fetch('/api/data')
.then(response => response.json())
.then(data => {
processData(data); // Забыли return
})
.then(result => {
console.log(result); // undefined
});
// ✅ Правильно - возврат значения
fetch('/api/data')
.then(response => response.json())
.then(data => {
return processData(data); // Возвращаем результат
})
.then(result => {
console.log(result);
});// ❌ Ошибка может быть утеряна
fetch('/api/data')
.then(response => response.json())
.then(data => {
throw new Error('Ошибка обработки');
})
.then(result => {
console.log(result);
});
// ✅ Правильная обработка
fetch('/api/data')
.then(response => response.json())
.then(data => {
throw new Error('Ошибка обработки');
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error('Ошибка:', error);
});Понимание возвращаемых значений методов Promise позволяет создавать более предсказуемый и надежный асинхронный код, избегая распространенных ошибок при работе с цепочками асинхронных операций.
Хотите больше статей для подготовки к собеседованиям? Подписывайтесь на EasyAdvice, добавляйте сайт в закладки и совершенствуйтесь каждый день 💪