Takazudo hamalog

programming notes. mainly about JavaScript / jQuery. [@Takazudo] [takazudo@gmail.com] Hint: alt + /

cool guy

jQuery.Deferredって何

2011/05/03 permalink

jQuery1.5から追加された機能。でも全然使ってないので調べた。

jQuery1.5からはdeferredオブジェクトっていうものが登場。
これは、「イケてるキュー(待ち行列)の仕組み~遅延もあるよ~」みたいなものです・・・
説明がムズイけれどもなんかそんな感じなのです。今までは

function fetch(callback){
    doAjaxThings('somefile.json', function(data){
        callback(data);
    });
}

fetch(function(data){
    doSomething(data.property);
});

みたいにコールバック渡さないといけなかったやつを

function fetch(){
    return doAjaxThings('somefile.json');
}
fetch().done(function(data){
    doSomwthing(data.property);
});

とか書ける。後でコレするっていうのをコールバックとして渡すところを、deferredオブジェクトというものを受け取ることで、チェーンチェーンで続きの処理をかけるって言う感じ。言葉にするとさっぱりなのですが、何かそんな感じです。(自分の理解も正直その程度)

var dfd = jQuery.Deferred();

jQuery.Deferred() は deferredオブジェクトのファクトリー。

deferredObject.then(fn)

終わったらハイこれやってねメソッド。

var dfd = $.Deferred();
dfd.then(function(){
    msg('オワタ1');
}).then(function(){
    msg('オワタ2');
    setTimeout(function(){
        msg('asyncなやつはかんけーないし。');
    },1000);
}).then(function(){
    msg('オワタ3');
});
dfd.resolve();

結果

  • オワタ1
  • オワタ2
  • オワタ3
  • 1秒後:asyncなやつはかんけーないし。

.resolve(); やると走る。
まーこんな風には使わないが前提知識として。
これだけだと、ただのキューみたいに見える。 

ajaxなやつら

deferred導入のタイミングで、ajaxなやつらは全てdeferredオブジェクトを返すようになった。
なので、こんな風に書ける。

$.ajax(url, ajaxOpts).then(function(data){
    outTweets(data);
}, function(){
    msg('OMG twitter seems to be down shit');
});

thenの第二引数には失敗した時に実行されるfunctionを指定。
ちなみに以下のような書き方もできる。

$.ajax(url, ajaxOpts).success(function(data){
    outTweets(data);
}).fail(function(){
    msg('OMG twitter seems to be down shit');
});

なのでコールバック渡すんじゃなくて、deferredオブジェクト返してくれれば後はこっちでうまくやるわーってできる。ajaxなやつらは、実行したら、取ってくるまで待つ感じ。これを次で解説。

promise / resolve / reject

ここからが本番。
deferredを使うと、「後でなんか返すからちょっと待っててよ」ができる。これがpromise。そして、なんかしらの非同期な処理が終わった時、「はい終わったぜ!」がresolve。「ごめん…ダメだった…」がreject。

/* promise returner */
function doAsyncThing(){
    var dfd = $.Deferred();
    var timeA = aFewMilliSec();
    var timeB = aFewMilliSec();
    setTimeout(function(){
        dfd.resolve('something seems to be successed.', timeA);
    }, timeA);
    setTimeout(function(){
        dfd.reject('something seems to be failed.', timeB);
    }, timeB);
    return dfd.promise();
}

/* do it */
doAsyncThing().then(function(res, time){
    msg('<b>success:</b> ' + res + '(time: ' + time + ')');
}, function(res, time){
    msg('<b>failed:</b> ' + res + '(time: ' + time + ')');
});

ちと微妙な例だけれどもA,Bの2個のタイマー走らせて、Aの方が早かったら成功、Bの方が早かったら失敗にしてみた例。とりあえずpromiseして返して、後でresolveという流れ。

ajaxなやつらは、実行時にpromiseして、取ってこれたらresolve、だめだったらrejectする感じ。

jQuery.when()

このjQuery.whenってやつがかなりいけてる。
これは、全部終わったらコールバック実行するわーというようなやつ。
こんな使い方しないけど、例えばこんなの。

/* dummy fn */
function fn(){
    return 4;
}

/* do it */
$.when( { num:1 }, 2, '3', fn() ).done(function(o1, o2, o3, o4){
    msg(o1.num);
    msg(o2);
    msg(o3);
    msg(o4);
});

whenの引数が全部処理されると、コールバックにその結果を引数として渡して実行する。whenの引数ってのは、基本なんでもあり風。

そしてミソなのが、このwhenには、deferredオブジェクトも渡せるってこと。deferredオブジェクトが混ざっていた場合、それらがすべて完了してからコールバックを実行する。つまり、並列で非同期の処理を行わせることが出来る。ここでpromise, resolve, rejectを使う。

/* functions */
function asyncThing1(){
    var dfd = $.Deferred();
    setTimeout(function(){
        msg('asyncThing1 seems to be done...');
        dfd.resolve('banana');
    },1000);
    return dfd.promise();
}
....

/* do it */
$.when( asyncThing1(), asyncThing2(), asyncThing3() ).done(function(res1, res2, res3){
    msg('all done!');
    msg(res1 + ', ' + res2 + ', ' + res3);
});

最低4秒待つみたいなこと

これを応用すると、例えば「非同期処理するんだけど最低4秒待つ」みたいなことができたりする。

/* utils */
....
function fetchTweets(){
    var url = 'https://api.twitter.com/1/statuses/public_timeline.json?';
    var ajaxOpts = { dataType: 'jsonp', callback: 'callback' };
    return $.ajax(url, ajaxOpts);
}
function wait4sec(){
    var dfd = $.Deferred();
    setTimeout(function(){
        dfd.resolve();
    }, 4000);
    return dfd.promise();
}

/* do it */
$(function(){
    startLoading();
    $.when(fetchTweets(), wait4sec()).then(function(ajaxResArgs){
        endLoading();
        var tweets = ajaxResArgs[0];
        outTweets(tweets);
    }, function(){
        msg('OMG twitter seems to be down shit');
    });
});

その他色々

こんな感じで色々と非同期処理を便利にしてくれるのがdeferredオブジェクト。しかしまぁ、ふーむ分かったけどどー使うんかいってのがいまいちしっくりこないです?そんなdeferredオブジェクトの色々な応用例が以下に紹介されてる。ちょっと自分もまだ完全に理解してないんだけども、キャッシュして2度目はリクエストしないとかそんな用途が一番使いそう。

公式サイトの解説にそこまで突っ込んで書いてないので触って覚えると良さそう。ほか、jQuery conferenceのビデオが分かりやすかった。

あ、あと、jQuery1.6で色々メソッドが増えた。

blog comments powered by Disqus

  1. junerhamalogからリブログしました
  2. haru012hamalogからリブログしました
  3. dobinn69hamalogからリブログしました
  4. shiridesignhamalogからリブログしました
  5. hakuraihamalogからリブログしました
  6. soplanahamalogからリブログして、コメントを追加しました:
    なるほど
  7. kzhrkhamalogからリブログしました
  8. jsakamotohamalogからリブログしました
  9. gortoncodehamalogからリブログしました
  10. funghiinihamalogからリブログしました
  11. fkeihamalogからリブログしました
  12. atm09tdsarabandejpからリブログしました
  13. sarabandejphamalogからリブログしました
  14. sibukixxxhamalogからリブログしました
  15. kanazawajshamalogからリブログしました
  16. yuzuemonhamalogからリブログしました
  17. dwenomohamalogからリブログしました
  18. mikage-sawatariharu012からリブログしました
  19. hamalogの投稿です