jQuery の Deferred でのエラー処理 その(1)
この内容は jQuery 1.7.2 を元に記述しています。
jQuery の Deferred の使い方はそこら中にでてるのですが、詳細なエラー処理の動きについてはあまり見つからないので調べてみました。ってことで、複数回に分けて書いてみます。
とりあえず、非同期処理のファンクションとして以下のようなのを使ってます。第3引数に true を設定すると、reject でマークされるようにしてます。
var async = function(value, timeout, reject){ var deferred = $.Deferred(); console.log("start - " + value); setTimeout(function(){ console.log("end - " + value); if(reject){ deferred.reject(value); }else{ deferred.resolve(value); } }, timeout); return deferred.promise(); };
reject された場合は、通常、 then の第2引数または fail にコールバックを設定することで取得できます。
async("test", 1000, true).then(null, function(e){ console.log("then - " + e); }).fail(function(e){ console.log("fail - " + e); });
結果は以下のような感じ。
基本はこれですが、例えば、複数のデータを取得したくてサービスコールしたら、サービスの動きがイケてなくて 0 件の場合に 404 とかを返されるとかありますよね。でも、アプリケーション的には 404 のエラーではなくって 0 件のデータとして扱いたい。
ってことで、 reject されたときでも、内容によっては resolve にしたいことがあります。
Deferred のインターフェイス的にはなんとなく、 then で繋いでいって、 done / fail で最後処理をするように見受けられます。ってことで、 then の時に、 resolve でマークされた Deferred を返せば done が実行されるとうれしいです。
async("test", 1000, true).then(null, function(e){ console.log("then - " + e); if(true /*本当はなにかの判定処理*/){ return $.Deferred().resolve(e); } }).done(function(e){ console.log("done - " + e); }).fail(function(e){ console.log("fail - " + e); });
これで done が実行されれば嬉しかったのですが、そうではなかったです。
どうやら then では、書き換えられないようですね。なんか、 promise を繋いでいくのではなく、 promise の結果を取得して、処理を行う口になっているだけみたいです。どうもインターフェイスのイメージに合わないです。
で、これを実現するためにはどうするかを探したら pipe ってのがありました。どうやらこれが繋いでいく関数のようです。なんか、 then ってなんなのよってなりそうです。
// then じゃなくて pipe async("test", 1000, true).pipe(null, function(e){ console.log("then - " + e); if(true /*本当はなにかの判定処理*/){ return $.Deferred().resolve(e); } }).done(function(e){ console.log("done - " + e); }).fail(function(e){ console.log("fail - " + e); });
結果は期待通りです。
さてさて、基本的なところはここまでですが、本来は複数の非同期処理をまとめて行いたいときに、できるだけネストをなくしてストレートに書いて結果を取りたいってのが Deferred の強みのはずなので、次回以降は pipe でのシーケンシャル実行の際のエラー処理と、 when でのパラレル実行の際のエラー処理を書きたいと思います。