t-sanoブログ

メモです。マイペースにアウトプットします。

jQueryのDeffered、whenを使いこなして、非同期処理のコールバック地獄から抜け出す

ubw.hatenablog.com

先日、S3に対して署名付きURLを用いて、大容量のファイルを分割してアップロードするということをやりました。 こちらをブラウザから非同期で実施する際に、コールバック処理をうまく制御する方法について、とても勉強になったのでメモします。

やりたいこと

ざっくり言うと、非同期処理で、ブラウザからS3にファイルをマルチパートアップロードすることです。 具体的には、下記のような処理を実現することになります。

  1. APIサーバに署名付きURLの発行リクエスト
  2. (1の処理が完了したら)APIサーバから受け取った署名付きURLに対してマルチパートアップロード
  3. (2の処理が完了したら)APIサーバにマルチパートアップロードの完了リクエスト

補足すると、上記、1と3は1回の非同期処理、2については複数回の非同期処理になる。 2では、並列にファイルをアップロードし、アップロード処理を素早く完了させたい。

jQuery.Defferedで処理の完了結果を通知する

1の処理が完了 -> 2の処理実行という流れを作るため、下記のようにDefferedを利用した。 簡単に言うと、関数内でDefferedのpromiseを返し、非同期処理が完了後、結果(成功だったらresolve、失敗だったらreject)をpromiseに返す。 Defferedの使い方について書こうと思ったのですが、本記事の一番下に記載している参考リンクをご覧になったほうが、 かなり参考になるため、ここで記載するのはやめておきます。

function hoge(){
  dfd = $.Deferred()

  $.get(requestUrl, requestParam
  ).done(function(data){
    dfd.resolve data
  }).fail(function(){
    dfd.reject
    alert '処理に失敗しました。'
  })

  return dfd.promise()
}
hoge().then(function(data){
  console:log('非同期処理の結果:');
  console.log(data);
})

whenを利用し、非同期処理を並列連結し、完了結果を通知する

2の処理が完了(並列実行) -> 3の処理実行という流れを作るため、下記のようにwhenを利用した。 whenを利用すると、複数のpromiseをまとめて、新しいpromiseを返してくれます。 これにより、すべてのpromiseで結果が帰ってきたら、次の処理に移行することができます。 こちらも参考リンクがとても参考になります。

dfds = []

$.each(array, function(index, value){
  dfd = new $.Deferred()

  $.ajax(
    url: value
    type: 'PUT'
    data: data[index]
    cache: false
    contentType: false
    processData: false
  ).done(finction(data){
    dfd.resolve()
  }).fail(function(){
    alert '処理に失敗しました。'
    dfd.reject()
  })
  dfds.push(dfd.promise())
})

$.when.apply($, dfds).done(hogehoge())

参考

techblog.yahoo.co.jp