非同期処理をちゃんと理解するぞ!
ということで,昨日(コールバックをちゃんと理解したい①)に引き続きコールバックやっていきます。
非同期的なエラーを例外処理する
非同期処理では同期処理のようにtry-catch構文を使って非同期的なエラーをキャッチすることができません。
コールバック関数内でtry-catch構文を使ってエラーをキャッチすることができるが,非同期処理の外からは非同期処理の中で例外が発生したかわかりません。
エラーファーストコールバック
(Promiseが仕様にはいるまでは)非同期処理で例外処理を行う場合は,エラーファーストコールバックというルールに則ることで例外処理が行われていました。
どういったルールかというと
- 処理が成功したら,コールバック関数の1番目の引数をnull,2番めの引数に成功時の結果を渡して呼び出す
- 処理が失敗したら,コールバック関数の引数にエラーオブジェクトを渡して呼び出す
実際のコードは以下のようになります。
// 非同期処理
// valueに値が入っている場合は成功,それ以外の場合は失敗
const asyncFunc = (value, callback) => {
setTimeout(() => {
if(value) {
callback(null, {"value": value});
} else {
callback(new Error("Failed"));
}
}, 3000);
};
// 成功する場合
asyncFunc('ばりゅー', (error, response) => {
if(error) {
console.log(error.message); // この行は実行されない
} else {
console.log(response); // → { value: 'ばりゅー' }
}
});
// 失敗する場合
asyncFunc(null, (error, response) => {
if(error) {
console.log(error.message); // → Failed
} else {
console.log(response); // この行は実行されない
}
});
その他にも
成功したとき用のコールバック関数と失敗したとき用のコールバック関数の2つを受け取るパターンもあります。
実際のコードは以下になります。
// 非同期処理
// valueに値が入っている場合は成功,それ以外の場合は失敗
const asyncFunc = (value, successCallback, failureCallback) => {
setTimeout(() => {
if(value) {
successCallback({"value": value});
} else {
failureCallback(new Error("Failed"));
}
}, 3000);
};
// 成功する場合
asyncFunc('ばりゅー', (response) => {
console.log(response); // → { value: 'ばりゅー' }
}, (response) => {
console.log(response.message); // この行は実行されない
});
// 失敗する場合
asyncFunc(null, (response) => {
console.log(response); // この行は実行されない
}, (response) => {
console.log(response.message); // → Failed
});
個人的にはこちらのほうがわかりやすいなーという印象です。
この書き方も,エラーファーストコールバックもあくまで共通のルール(手法)なので,
強制力はなく,書こうと思えば書きたいように書くことができます。
なのでルールではなく仕様として非同期処理を扱う方法が求められ,ES2015よりPromiseオブジェクトが導入されました。
まとめ
コールバックにどんな問題があって,Promiseオブジェクトが導入されたのかっていう経緯がわかりました。
なんとなく,Promiseやasync/awaitを使って非同期処理をやっていたけど,この歴史をたどる感じが真の理解へと近づけてくれている気がします。
手法だけじゃなく,背景や目的,経緯がわかってくると見えてくるものがあるなと感じます。
明日からはPromiseオブジェクトやるぞー
それではまた明日。