jQueryのDeffered、whenを使いこなして、非同期処理のコールバック地獄から抜け出す
先日、S3に対して署名付きURLを用いて、大容量のファイルを分割してアップロードするということをやりました。 こちらをブラウザから非同期で実施する際に、コールバック処理をうまく制御する方法について、とても勉強になったのでメモします。
やりたいこと
ざっくり言うと、非同期処理で、ブラウザからS3にファイルをマルチパートアップロードすることです。 具体的には、下記のような処理を実現することになります。
- APIサーバに署名付きURLの発行リクエスト
- (1の処理が完了したら)APIサーバから受け取った署名付きURLに対してマルチパートアップロード
- (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())