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.
その結果、エラーはシステム全体に伝播せず、クラッシュにつながりますが、コードのスコープ内で直接処理されます。アプリやサービスがクラッシュすることはなく、エラーを処理するための軽減戦略を適用できます。
「最終的に」ブロックによる特別な取り扱い
エラーを処理するための追加の手順として、JavascriptとTypescriptは追加の「最終的に」キーワードを提供します。このような「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 ...
しかし、待ってください、もっとあります! 「try」または「catch」ブロックで結果を返しても、「finally」ブロックが実行されることをご存知ですか?これが私が意味することの例です。
// 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」ブロックを使用するときに知っておくと便利ですが、アンチパターンスタイルでコードを実装することを避けるために悪用しないでください。