jQueryで非同期処理の完了を待つ(jQuery.Deferred())

 jQueryのAJAX実装をすると、通常、通信が戻ってくるのを待たずに次の処理に進んで、通信の結果はコールバックで処理するよね。

function getResponse(url, parameters, target){
  jQuery.post(url, parameters, function(response){
    for(i in response){
      $(target).html(response[i]);
    }
  });
}

みたいな感じね。

 でも、この処理をまたどこからか呼び出していて、呼び出し元で、この通信が終了している必要がある場合(たとえばappendした結果に対して何か処理したいとか)、普通に

getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’);
alert($(‘#targetArea’).html());

とかすると、getResponseは要求を作っただけで戻ってきてしまうので、alertの中身は空っぽ、みたいな事になる。
で、これに対応するためにどうするかというと、jQueryのDeferredを使うと良いようだ。

ファンクションの方は

function getResponse(url, parameters, target){
  var def = jQuery.Deferred();
  jQuery.post(url, parameters, function(response){
    for(i in response){
      jQuery(target).html(response[i]);
    }
    def.resolve();
  });
  return def.promise();
}

みたいな感じで、Deferred.promise()を戻すようにする。
AJAXの戻り値を待つ必要がない既存のコードは、特に何も変えなければそのまま動く。 そして、先のように待機する必要がある場合のコードでは、

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(){
    alert($(‘#targetArea’).html());
  }
);

みたいな感じにすると、getResponseが返したDeferredがresolveを実行次第doneの中身が呼び出される。
done()は、Deferredにバインドしている形なので、

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(){
    alert($(‘#targetArea’).html());
  }
);
window.close();

みたいにすると、表示してから閉じると言う動きにはならず、すぐ閉じてしまう。

なお、失敗時のために、resolve doneの組み合わせに対して、reject failがある。。

jQuery.when( asyncFunc() ).done( trueFunc() ).fail( failFunc() );

みたいにすれば、asyncFunc()の返したDeferredでresolve()が実行されればtrueFunc()を、reject()が実行されればfailFunc()が実行されるようになる。

 ファンクションが何かの値を戻していた場合、普通に書き換えるとDeferredを戻さなくてはならなくなると言う問題があるが、resolve/rejectに引数として与えると、done/failの引数として引き継がれる。

function getResponse(url, parameters, target){
  var def = jQuery.Deferred();
  jQuery.post(url, parameters, function(response){
    for(i in response){
      jQuery(target).html(response[i]);
    }
    def.resolve(response.length);
  });
  return def.promise();
}

jQuery.when(
  getResponse(‘http://hoge.tld/piyo.php’, {‘request’:’getMessage’}, ‘#targetArea’)
).done(
  function(len){
    alert(len + ‘:’ + $(‘#targetArea’).html());
  }
);

みたいな感じ。

whenはDeferredを複数くっつけるための物なので、1個の実行を待つだけならDeferredを戻すファンクションに対して、 asyncFunc().done(trueFunc()) 的な呼び出しでも良いっぽい。

(10548)


カテゴリー: jQuery   パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です