Promise処理の中での例外エラーの扱いについて
JavaScriptで開発するにあたってPromise処理は欠かせません。非同期処理が頻繁に使われるため、前の処理が適切に終了したのか、または失敗したのかを通知する仕組みとしてPromiseが使われます。
通常、Promiseは次のような記述となります(hifiveでの記述です)。testという関数が非同期処理である場合、その結果を受け取ってthenまたはfailに送信されます。
var deffered = h5.async.deferred();
var test = function (count) {
setTimeout(function () {
try {
console.log('count', count);
if (count === 1) {
deffered.resolve(count)
} else {
throw count;
}
}
catch(err) {
return deffered.reject(err)
}
}, 1000);
};
var promise = deffered.promise();
test(1);
promise.then(function(msg) {
console.log("success", msg);
}).fail(function(msg) {
console.log("fail", msg);
});
Promise内では処理が成功したらresolve、失敗したらrejectを呼び出します。そのため分かりやすい形としては処理全体をtry/catchで囲んでしまい、何か問題があればcatchに飛ばしてしまうことです。もちろんコード内でもrejectに飛ばす場合もあるでしょう。
上記処理を実行すると、
count – 2
success 1
というログが出ます。
thenの中でエラーが起こるとどうなるか
さて、例えば then 処理の中で例外処理が起こった場合はどうなるでしょうか。コードとしては次のようになります。
var deffered = h5.async.deferred();
var test = function (count) {
setTimeout(function () {
try {
console.log('count', count);
if (count === 1) {
deffered.resolve(count)
} else {
throw count;
}
}
catch(err) {
return deffered.reject(err)
}
}, 1000);
};
var promise = deffered.promise();
test(1);
promise.then(function(msg) {
console.log("success", msg);
throw 2; // 追加
}).fail(function(msg) {
console.log("fail", msg);
});
期待するところとしては、.fail
が呼び出されることかも知れませんが、実際にはそうはなりません。すでにPromiseとしては処理が完了しているためです。
ただし、流れとしては try/catchに囲まれた場所であるために catch が呼び出されます。ただしこの後に deffered.reject(err)
を呼び出しても何も起こらないようです。
ES6ではどうなるのか
ECMAScript6では標準でPromiseが搭載されます。その場合は次のような記述になります。
var promise = new Promise(function(resolve, reject) {
setTimeout(function () {
var count = 1;
try {
console.log('count', count);
if (count === 1) {
resolve(count)
} else {
throw count;
}
}
catch(err) {
console.log("Error!")
return reject(err);
}
}, 1000);
});
promise.then(function(msg) {
console.log("success", msg);
throw 2;
console.log("Exception called");
}, function(msg) {
console.log("fail", msg);
});
ECMAScript6の場合、Promiseはthenのみがあり、一つ目がresolve、二つ目がreject相当になります。上記のようなコードの場合、
count 1
success 1
Uncaught (in promise) 2
といったログが表示されます。二つ目の関数に飛ぶわけではありません。
Promise自体、ようやく標準化が定まった状態で、jQuery 3系でも修正が予定されています。今後はECMAScript6に沿った形になっていくことでしょう。then処理内での例外発生は予定していなかった場所がコールされる可能性があるので注意が必要そうです。
コメントは受け付けていません。