Skip to content
Tags

Promise処理の中での例外エラーの扱いについて

by : 2016/02/22

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処理内での例外発生は予定していなかった場所がコールされる可能性があるので注意が必要そうです。

From → hifive

現在コメントは受け付けていません。

%d人のブロガーが「いいね」をつけました。