こんにちは。きんくまです。
今回はjQuery.Deferredです。
これは、非同期処理をわりと簡潔に書けるようになるので、ソースコードがあっちにいったり、こっちにいったりしないで、見やすくなるのが便利ポイントかなと思いました。
ASでもCommand系のライブラリがあったので、使用感としてはそれに近い感じでしょうか。並列、直列の非同期を書けるところとか。
で、わかりやすいチュートリアル記事があったので、これで勉強デス。
>> 爆速でわかるjQuery.Deferred超入門
ためしに書いたタイマーの非同期処理
var myTimer = function(){ var d = new $.Deferred(); setTimeout(function(){ console.log('timer complete'); d.resolve(); }, 1000); console.log('timer start'); return d.promise(); } myTimer() .then(myTimer) .then(function(){ console.log('all tasks complete'); });
これやってて、例えば登録時(.then)に引数をもたせたいことって結構あると思います。
3秒待ってから、5秒待ってからとか。
なので、ためしに引数をもたせてみてもうまくいかないのですよね。
登録時に実行してしまって、関数を登録していないのが問題。
var myTimer = function(delayTime){ var d = new $.Deferred(); setTimeout(function(){ console.log('timer complete'); d.resolve(); }, delayTime * 1000); console.log('timer start'); return d.promise(); } myTimer(2) .then(myTimer(3)) .then(function(){ console.log('all tasks complete'); });
また.thenに登録する関数の引数は実行時に前の.promise()の中に入る引数が入っているということもあります。
日本語よくわからないと思うので、コードで説明
var myTimer = function(){ var d = new $.Deferred(); setTimeout(function(){ d.resolve('next message'); }, 1000); console.log('timer start'); return d.promise(); } myTimer() .then(function(msg){ console.log(msg); });
前のタイマーのresolveで入れた文字列が、次の.thenの中のmsgに入っています。
今回は文字列いれましたけど、配列でもObjectでも何でも入れて大丈夫です。
で、引数つきの関数の件は最終的に
var myTimer = function(delayTime){ return function(){ var d = new $.Deferred(); setTimeout(function(){ console.log('timer complete'); d.resolve(); }, delayTime * 1000); console.log('timer start delay ' + delayTime); return d.promise(); } }
とかやっておけば大丈夫でした。
ためしに、画像読み込みなども作ってみました。これで引数つけて登録できるので便利かなと。
var asyncLoadImage = function(path){ return function(){ var d = new $.Deferred(); var img = new Image(); img.onload = function(){ console.log('load image complete'); d.resolve(); } img.src = path; console.log('start load image'); return d.promise(); } } var myTimer = function(delayTime){ return function(){ var d = new $.Deferred(); setTimeout(function(){ console.log('timer complete'); d.resolve('resolved message'); }, delayTime * 1000); console.log('timer start delay ' + delayTime); return d.promise(); } } var logMsg = function(firstMsg){ return function(resolvedMsg){ console.log(resolvedMsg); console.log(firstMsg); }; } myTimer(2)() .then(logMsg('hello')) .then(asyncLoadImage('images/sample1.gif')) .then(myTimer(3)) .then(function(){ console.log('all tasks complete'); });
で考えてみると、.then()のときに.promise()を返す関数を登録すればよいので、クラスでもふつうに使えます。
var ImageLoader = function(path){ this.deferredObj; this.path = path; this.init(); }; ImageLoader.prototype = { init:function(){ this.deferredObj = new $.Deferred(); }, loadImage:function(){ var self = this; var img = new Image(); img.onload = function(){ console.log('load complete'); self.deferredObj.resolve(); }; img.src = this.path; console.log('load start'); return this.deferredObj.promise(); } } //myTimerはひとつ前のコードから拝借したと思ってください。 myTimer(2)() .then(function(){ var loader = new ImageLoader('images/sample1.gif'); return loader.loadImage(); }) .then(function(){ console.log('all tasks complete'); })
これ使って、よくFlashのときにやってた、FadeInとかのTween系とか、画像や外部テキストの読み込み処理を、クラス化したりすると便利かなーと思いました。
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ