たとえばsetTimeoutで1秒ごとの処理を順次実行したい場合、よくあるサンプルを元に$.Deferredで書くと、以下の実行結果が1秒後に全部表示されてしまいました。
delay:0
delay:1
delay:2
delay:3
delay:4
tasks done.
やりたいのは0〜4までを1秒ごとに(確実に完了してから)実行すること。
以下のように書いたら解決しました。
// 順次実行したいメソッド
var delay = function (param) {
return function(){
var $deferred = new $.Deferred();
setTimeout(function(){
console.log('delay:'+param);
$deferred.resolve();
}, 1000);
return $deferred.promise();
}
};
// タスクを詰め込むDeferredを用意
var tasks = (new $.Deferred()).resolve();
// タスクを登録
for(var i = 0; i < 5; i++){
tasks = tasks.then(delay(i));
}
tasks.done(function(){
console.log('tasks done.');
});
ポイントはdelayをreturn functionで返す点。
普通に書いてしまうと tasks.then(delay(i))
の時点で実行されてしまうので1秒後に0〜4が一気に実行されてしまいました。
まあ当然といえば当然ですがこれに気がつくのに非常に時間が掛かったのでメモ。