Какая конструкция может использоваться вместе с try-catch в JavaScript
Что проверяют
Знаете ли вы полную форму конструкции и что происходит с потоком выполнения в каждом блоке. У Android-разработчика такой вопрос обычно всплывает рядом с WebView или React Native, поэтому следом часто просят сравнить обработку ошибок с Kotlin и Java.
Как отвечать
Ответ на сам вопрос: finally. Полная форма try { } catch (e) { } finally { }, допустима и пара try...finally без catch. Дальше про поведение:
finally: выполняется всегда: при нормальном завершении, послеcatchи даже когда вtryстоитreturn. Туда кладут освобождение ресурсов, снятие индикатора загрузки, сброс флагов;returnвнутриfinally: перекрывает и результатtry, и выброшенную ошибку, которая при этом молча теряется;throw: бросить можно что угодно, но принято бросатьErrorили наследника, чтобы сохранился стек. С ES2022 причина передаётся черезnew Error("...", { cause: e });catchбез параметра: с ES2019 можно писатьcatch { }, если сама ошибка не нужна.
Про асинхронность обязательно: try/catch ловит отклонённый промис только при await внутри try. Промис без await упадёт мимо блока. Для цепочек есть .catch() и .finally().
Сравнение с Kotlin, которого от вас ждут: там тоже try/catch/finally, но try является выражением и возвращает значение, а проверяемых исключений нет, как и в JS. Для ресурсов вместо ручного finally используют use { } у Closeable, в Java это try-with-resources. В корутинах есть тонкость: CancellationException нельзя проглатывать общим catch (e: Exception), иначе отмена корутины перестанет работать.
Где спотыкаются
Называют catch и throw, но забывают finally, хотя спрашивают именно про него.
Уверены, что try/catch вокруг fetch(url).then(...) без await поймает сетевую ошибку. Не поймает: промис отклонится уже после выхода из блока.
Пишут return в finally «для надёжности» и прячут исключение, а потом не могут понять, почему функция вернула странное значение.