Что такое finally в промисах и для чего он используется
Что проверяют
Знаете ли вы семантику finally точно: что он не меняет результат цепочки, но испортить его вполне может. Короткий вопрос с подвохом, по ответу видно, читал ли человек спецификацию или запомнил, что этот блок выполняется всегда.
Как отвечать
finally регистрирует обработчик, который сработает при любом исходе промиса, и нужен для завершающих действий: снять индикатор загрузки, разблокировать кнопку, освободить ресурс. Он убирает дублирование одного и того же кода в then и catch.
Три свойства, которые и проверяют:
- обработчик вызывается без аргументов. Ни значения, ни причины отказа он не получает, и это осознанно:
finallyне про результат; - исходный результат проходит насквозь. Успех остаётся успехом, отказ остаётся отказом, обычное значение, возвращённое из обработчика, игнорируется;
- испортить результат всё же можно. Если обработчик бросит исключение или вернёт отклонённый промис, дальше по цепочке уйдёт уже эта причина вместо исходной, а возвращённый промис будет дождан, то есть завершение отложится.
setLoading(true);
fetchUser(id)
.then(render)
.catch(showError)
.finally(() => setLoading(false));Добавьте, что finally не обрабатывает отказ: после него цепочка остаётся отклонённой, и catch всё равно нужен. В асинхронной функции ровно то же самое даёт обычный try с блоком finally, и в новом коде чаще пишут именно так.
Где спотыкаются
Считают finally заменой catch. Ставят его последним, ошибку не ловят, в консоли появляется необработанный отказ, а пользователь не видит никакого сообщения.
Кладут в обработчик логику, способную упасть. Исключение оттуда подменяет настоящую причину отказа, и разбор инцидента начинается с ложного следа.
Пишут возврат значения внутри обработчика в надежде подменить результат. Обычное значение там просто отбрасывается, а вот промис задержит завершение цепочки, и это неожиданно сказывается на порядке отрисовки.