2013
05/28

Ajaxじゃなくても使える、$.Deferredで好きな処理を連鎖的に実行する方法

5/30追記
Deferredについて相当に誤解していましたので、以下の内容は信用しないでください。後日修正します。。。。
間違って解釈していた点について@yuka2pyさんに詳しく教えていただき、まとめていただきました。勉強になります、ありがとうとざいます。

6/4追記
追記しました。返り値として渡すべきものが何か分かっていなかった点が問題でした。

$.DeferredはjQuery1.5より実装された非同期処理を扱うためのオブジェクトです。
$.Deferredについての解説記事やサンプルコードは検索すれば多く見つかりますが、大抵Ajaxの非同期処理での利用方法となっています。

ですが$.DeferredはAjaxでなくても、アニメーションなどの処理を連鎖的に実行する際にも利用することができます。
実務的にはAjaxよりも連鎖的な処理として利用するほうが頻度が高いと思いますので、参考にしてみてください。

ADs

基本的な記述

まず順次実行したい処理を返り値をfunctionとする関数として定義します(以下の例のfunc01,func02…がそれにあたる)。
言葉で書くと難しいように見えますが、普段jQueryを使って書いているメソッドの頭にreturnをつけるだけです。

そして実行したい順番にthen()でつなぎ、最後にresolve()で実行します。

2013.06.04追記
返り値として返すべきものはfunctionではなく、promiseオブジェクトでした。
よくDeferredの事例としてsetTimeoutを使った以下の様なコードが紹介されていますが、これを見てみると返り値としてd.promise(); とpromimseオブジェクトを返しています。

アニメーション関連の処理の場合はjQuery1.8より返り値としてpromiseオブジェクトを返すようになりましたので、結果的にpromimseオブジェクトを返しています。

$.Deferredの部分は実行したい順番につなぐだけなので、特に難しい点はないと思います。
関数定義の部分をいくつか具体的に書いてみました。

シンプルなアニメーションの場合

最も簡単な例ですが、単純なアニメーションの場合は頭にreturnをつけるだけです。
アニメーションの場合は完了後に処理をつないでいこうとするとコールバックまみれになってしまいますが、then()でつなぐことで書きやすく読みやすいコードとなります。

アニメーションではない処理の場合

同様に以下のようなスタイルを定義する処理も書くことができます。
アニメーションが終わったら背景色を変更して、次のアニメーションを実行する、というような連続した処理が可能となります。

2013.06.04追記
css()やattr()のような同期処理の場合はreturnとして返り値を返す必要はありませんでした。
単に

でよかったです。

$.eachを使った処理の場合

ループを使った処理は場合によっては時間がかかり、ループが完了しないうちに次の処理が走ってしまうことがありますが、そういった事態を避けることができます。
以下のようにdelayを使った場合でも、きちんとループ終了後に次の処理に移ることができます。

2013.06.04追記
上記の記述は間違ってはないのですが、each()の完了を待っているのではなく、複数登録されたfadeIn()の完了を待っています。
アニメーション関連の処理の場合、キューに登録されたすべてのアニメーション完了後にpromiseオブジェクトが返されます。

上記functionはeach()の完了を待っていたわけではなく、すべてのfadeIn()の完了を待っていた、ということです。

複数のオブジェクトに対する処理の場合

ここまでは1行で書ける処理ばかりでしたが、1行で書けない、つまり複数のオブジェクトに対する処理を同時に実行させる場合は以下のように一つの関数にまとめます。
ただのfunctionでは実行されませんので、即時関数にして実行されるようにします。

2013.06.04追記
ここも即時関数にする必要はなかったですね。

で問題ありません。

具体的な実行例

DEMO

ソースを見れば分かりやすいですが、

1.div.blockをフェードイン
2.div.itemを0.1秒おきに1個ずつフェードイン
3.div.itemを0.1秒おきに1個ずつフェードアウト
4.div.itemを0.1秒おきに1個ずつフェードイン
5.div.itemの背景を#00fに、div.blockの背景を#333に
6.div.itemを0.1秒おきに1個ずつフェードアウト
7.div.blockに「おつかれ!」という文字列をappned()

という処理を順番に行なっています。

$.Deferredを使わなければ7階層のコールバック地獄になっているかもしれませんが、極めてシンプルに記述することができます。

ADs

Post Comments

メールアドレスが公開されることはありません。

Comments

コメントはまだありません。