Обработка ошибок в Javascript и Typescript
Всякий раз, когда во время выполнения происходит ошибка, она «выкидывается» в Javascript и Typescript, как это имеет место в большинстве языков программирования. Необработанные выбросы ошибок приведут к сбою вашего приложения или службы, что приведет к наихудшему пользовательскому опыту. Если происходит ошибка, любой несохраненный прогресс теряется, и пользователи потенциально могут начать длительный процесс (например, если пользователь регистрировался на платформе, предоставляя много информации) снова и снова. В результате эти пользователи, скорее всего, никогда больше не будут использовать ваш продукт, так как доверие было потеряно.
Чтобы справиться с такими случаями, можно «отловить» ошибку. Чтобы отловить ошибки в Javascript и Typescript, вы просто заключаете свой код в блок «try», за которым следует блок «catch».
async function getData(){
try {
// Call a dummy async 'fetch'-functoin
const result = await fetch();
return { result };
} catch(error) {
return { error };
}
}
// ... later in your code ....
const { result, error } = await getData();
if (error){
// ... handle error case.
}
// Access the results.
В результате ошибка не распространяется на всю систему, что приводит к сбою, а обрабатывается непосредственно в рамках вашего кода. Приложение или служба не выйдет из строя, и можно применить стратегию устранения ошибки для обработки ошибки.
Особое обращение с блоком «finally»
В качестве дополнительного шага для обработки ошибок Javascript и Typescript предоставляют дополнительное ключевое слово «finally». Такой блок «finally» выполняет любой код в пределах своей области действия после того, как были выполнены как блок «try», так и блок «catch» (если произошла ошибка).
// This function is absolutely save
// to call. It fetches some data and
// optionally catches a potential error.
//
// After everything's done, a 'finally'
// sends the error to our backend for logs,
// if there was any.
async function getData(){
// In this case, we store the result
// and error in mutable variables,
// then return both.
let result: Result;
let error: Error;
try {
// Call a dummy async 'fetch'-function
result = await fetch();
} catch(e) {
error = e;
} finally {
// After the whole try/catch has been
// processed, we can log the error.
if(error){
await trackErrorInCloud(error);
}
}
return { result, error };
}
// ... same as before ...
Но подождите, это еще не все! Знаете ли вы, что блок «finally» выполняется, даже если вы возвращаете результат в блоке «try» или «catch»? Вот пример того, что я имею в виду.
// Same as the example before, but
// now we directly return from within
// each code block. And this is where
// a side effect can happen.
async function getData(){
try {
const result = await fetch();
return { result };
} catch(error) {
return { error }
} finally {
//
// WATCH OUT!
//
// Just for demo purpose, but this
// line of code will override both
// the return in 'try' as well as 'catch'!
//
// Returning inside of 'finally' is therefore
// dangerous and will lead to hard-to-debug
// issues.
return { finally: true };
}
}
// data === { finally: true }
const data = await getData();
// Here's a better use case for
// finally.
async function getData(){
let error: Error;
try {
const result = await fetch();
return { result };
} catch(e) {
error = e;
return { error }
} finally {
// No return in finally,
// so it's safe to use.
if(error){
await logInCloud()
}
}
}
// if no error === { result: ... }
// if error === { error: ... }
const data = await getData();
Резюме
Как вы видели, обработка ошибок в Javascript и Typescript довольно проста и позволяет избежать полного сбоя вашего приложения. Специальную обработку возврата результатов в блоках «try» и «catch» полезно знать при использовании блока «finally», но не следует злоупотреблять этим, чтобы избежать реализации кода в стиле анти-шаблона.