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);
});

結果は以下のような感じ。

f:id:k_maru:20120623161326p:plain

基本はこれですが、例えば、複数のデータを取得したくてサービスコールしたら、サービスの動きがイケてなくて 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 が実行されれば嬉しかったのですが、そうではなかったです。

f:id:k_maru:20120623163213p:plain

どうやら 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);
});

結果は期待通りです。

f:id:k_maru:20120623164304p:plain

さてさて、基本的なところはここまでですが、本来は複数の非同期処理をまとめて行いたいときに、できるだけネストをなくしてストレートに書いて結果を取りたいってのが Deferred の強みのはずなので、次回以降は pipe でのシーケンシャル実行の際のエラー処理と、 when でのパラレル実行の際のエラー処理を書きたいと思います。