前の関連記事:jQuery.Deferred学習メモ(2)jQuery1.8以降のdeferred.then()を使う
jQuery.Deferredオブジェクト以外でもPromiseを返すメソッドがあります。それらを使うとjQuery.Deferredオブジェクトを作らなくてもdeferred.then()でPromiseを返せます。まずはアニメーション関係のメソッドです。
.animate()はPromiseを返す。ただしPromiseに付随する引数は返せない。
jQuery.Deferred学習メモ(2)jQuery1.8以降のdeferred.then()を使うの最後にでてきたテストコード⑦を改造してsetTimeoutの変わりに.animate()を使って次の.always()を待たせてみます。
まずは普通にjQuery.Deferredオブジェクトを新たに作ってreturnするやり方です。
テストコード⑧
<script src="http://code.jquery.com/jquery-1.9.1.js"></script> <button id="btn1">未完</button><button id="btn2">完了</button><button id="btn3">失敗</button><br /> <div id="df_ex"></div> <script> var df1 = $.Deferred(); function fn1(n) { $( "#df_ex" ).append(df1.state()+n+"<br/>"); } function fn2(n) { var df2=$.Deferred(); var n2; fn1(n); $( "#df_ex" ).animate( {width: "70%", opacity: 0.4, marginLeft: "0.6in", fontSize: "3em"}, {duration:1500, easing: "linear", complete: function(){n2="で.alwaysも実行"; df2.resolve(n2);} } ); return df2; } df1 .then(fn2,fn2,fn1) .always(fn1) $( "button#btn1" ).on( "click", function() { df1.notify("で.progress実行"); }); $( "button#btn2" ).on( "click", function() { df1.resolve("で.done実行"); }); $( "button#btn3" ).on( "click", function() { df1.reject("で.fail実行"); }); </script>fn2の中で10行目で新たにjQeury.Deferredオブジェクトdf2を作っています。
テストコード⑦ではsetTimeoutの中でfn1(n)を実行しfn1の表示を1秒待たせていましたが、テストコード⑧ではまずfn1を表示させてそれを1.5秒かけて拡大表示のアニメーションにしています。
17行目でdf2をreturnして次の.always()の実行を待たせています。
アニメーション終了後の16行目のdf2.resolve(n2)で待たせているのを再開します。
「完了」ボタンをクリックしてみると、まず22行目の.then()のdoneFilterが実行されて9行目のfn2が呼ばれて12行目のfn1(n)が実行されて、「resolvedで.done実行」が表示されます。
続いて13行目の.animate()で1.5秒かけて字が大きくなって、その後に23行目の.alwaysが実行されて「resolvedで.alwaysも実行」が表示されます。
テストコード⑧では19行目でjQuery.Deferredオブジェクトのdf2をreturnしてunfulfilledのPromise返しましたが、今度は.animate()のPromiseを使ってみます。
テストコード⑨
<script src="http://code.jquery.com/jquery-1.9.1.js"></script> <button id="btn1">未完</button><button id="btn2">完了</button><button id="btn3">失敗</button><br /> <div id="df_ex"></div> <script> var df1 = $.Deferred(); function fn1(n) { $( "#df_ex" ).append(df1.state()+n+"<br/>"); } function fn2(n) { fn1(n); return $( "#df_ex" ).animate( {width: "70%", opacity: 0.4, marginLeft: "0.6in", fontSize: "3em"}, {duration:1500, easing: "linear"} ); } df1 .then(fn2,fn2,fn1) .always(fn1) $( "button#btn1" ).on( "click", function() { df1.notify("で.progress実行"); }); $( "button#btn2" ).on( "click", function() { df1.resolve("で.done実行"); }); $( "button#btn3" ).on( "click", function() { df1.reject("で.fail実行"); }); </script>11行目で.animate()メソッドをつけたjQueryオブジェクトをreturnしています。
「完了」ボタンをクリックしてみるとテストコード⑧と同様な動作をします。
これは.animate()の中でjQuery.deferredオブジェクトが作られて、それをresolveするということが行われているからです。
ですのでテストコード⑧の10行目と16行目に相当するコードは書かなくてもよいわけです。
でも、ちょっと表示されているものが違います?
実は、.then()ではPromiseの引数を返さないといけないのを返していないのです。
テストコード⑦では「で.alwaysも実行」となっていたところが「[object Object]」となっているのはそのためです。
この問題は$.when()を使って解決できました。
jQuery.Deferred学習メモ(5)jQuery.when()で複数PromiseのAND条件を判定のテストコード⑰へ。
引数をそのまま次へ受け渡すときは.then()でなく.done()を使えばいいでしょう。
今度はテストコード⑨で.animate()メソッドをつけたjQueryオブジェクトではなく引数をreturnしてみます。
テストコード⑩
<script src="http://code.jquery.com/jquery-1.9.1.js"></script> <button id="btn1">未完</button><button id="btn2">完了</button><button id="btn3">失敗</button><br /> <div id="df_ex"></div> <script> var df1 = $.Deferred(); function fn1(n) { $( "#df_ex" ).append(df1.state()+n+"<br/>"); } function fn2(n) { fn1(n); $( "#df_ex" ).animate( {width: "70%", opacity: 0.4, marginLeft: "0.6in", fontSize: "3em"}, {duration:1500, easing: "linear"} ); return "で.alwaysも実行"; } df1 .then(fn2,fn2,fn1) .always(fn1) $( "button#btn1" ).on( "click", function() { df1.notify("で.progress実行"); }); $( "button#btn2" ).on( "click", function() { df1.resolve("で.done実行"); }); $( "button#btn3" ).on( "click", function() { df1.reject("で.fail実行"); }); </script>15行目で単に引数だけreturnしています。
Promiseの引数はちゃんと受け継がれていますが、.then()の次の.alwaysの実行は待ってくれず、「resolvedで.alwaysも実行」が表示されてからアニメーションが始まります。
Promise animationを返すメソッド
.animate()以外にもアニメーションのメソッドはPromiseを返します。
jQuery API DocumentationでPromise animationを検索するとたくさんでてきます。
.fadeIn() .fadeOut() .fadeToggle() .hide().show() .slideDown() .slideToggle() .slideUp() .toggle()がでてきます。
Promise animationのPromiseは.promise()で引き出して.done()できる
テストコード⑨ではPromise animationのunfulfiledのPromiseを.then()にreturnして次のコードの実行を保留にしましたが、Promise animationのPromiseを.promise()メソッドで取り出すことも可能です。
テストコード⑧の16行目を書き換えて.animate()のPromiseを.promise()で取り出して.done()で受けて同じ処理をさせてみます。
テストコード⑪
<script src="http://code.jquery.com/jquery-1.9.1.js"></script> <button id="btn1">未完</button><button id="btn2">完了</button><button id="btn3">失敗</button><br /> <div id="df_ex"></div> <script> var df1 = $.Deferred(); function fn1(n) { $( "#df_ex" ).append(df1.state()+n+"<br/>"); } function fn2(n) { var df2=$.Deferred(); var n2; fn1(n); $( "#df_ex" ).animate( {width: "70%", opacity: 0.4, marginLeft: "0.6in", fontSize: "3em"}, {duration:1500, easing: "linear"} ).promise().done(function(){n2="で.alwaysも実行"; df2.resolve(n2);}); return df2; } df1 .then(fn2,fn2,fn1) .always(fn1) $( "button#btn1" ).on( "click", function() { df1.notify("で.progress実行"); }); $( "button#btn2" ).on( "click", function() { df1.resolve("で.done実行"); }); $( "button#btn3" ).on( "click", function() { df1.reject("で.fail実行"); }); </script>returnでPromise animationを返すとPromiseの状態に従って対応してくれるので、.animate().done()でいけそうに思いますが、これでは動かなくて.animate().promise().done()というように.promise()を間に挟まないといけないです。
これは.animate()の中で作られたPromiseがfulfilledになっときに.done()するということです。
.done()の他に.then(), .fail(), .always(), .progress(), .state()も使えるようです。
Promiseを理解したあとならテストコード⑧の書き方よりこのテストコード⑪の書き方の方がわかりやすいかもしれませんね。
参考にしたサイト
animate(params, options) - jQuery 日本語リファレンス
.animate()の第2引数以降をオプションで指定するやり方の解説。
.animate() | jQuery API Documentation
本家の.animate()の解説。
.animate() | 私的なjQuery
日本語で詳しく.animate()が解説されています。
.promise() | jQuery API Documentation
.promise()の本家の解説。
0 件のコメント:
コメントを投稿