同期関数と非同期関数を特定の順序で実行したい場合は、jQuery promiseを使用できますが、期待どおりに機能しないようです。
関数a、b、cは、deferred.resolve()
が呼び出されたときにこの順序で実行される必要があります。関数bが実行されることを期待しますが、resolveが呼び出されても、すべての関数はすぐに実行されます。
コードは次のとおりです。
function a(){
var deferred = $.Deferred();
setTimeout(function(){
console.log("status in a:",deferred.state());
//this should trigger calling a or not?
deferred.resolve("from a");
},200);
console.log("a");
return deferred.promise();
};
function b(){
var deferred = $.Deferred();
setTimeout(function(){
console.log("status in b:",deferred.state());
deferred.resolve("from b");
},200);
console.log("b");
return deferred.promise();
}
//synchronous function
function c(){
var deferred = $.Deferred();
console.log("c");
console.log("status in c:",deferred.state());
deferred.resolve("from c");
return deferred.promise();
}
function test(){
fn=[a,b,c],i=-1,
len = fn.length,d,
d = jQuery.Deferred(),
p=d.promise();
while(++i<len){
p=p.then(fn[i]);
}
p.then(function(){
console.log("done");
},
function(){
console.log("Failed");
});
d.resolve();
//instead of the loop doing the following has the same output
//p.then(a).then(b).then(c);
//d.resolve();
}
test();
出力は次のとおりです。
a
b
status in c: pending
c
done
status in a: pending
status in b: pending
期待される出力:
a
status in a: pending
b
status in b: pending
c
status in c: pending
done
次の変更のいくつかの組み合わせを試しました。
d = jQuery.Deferred();
setTimeout(function(){d.resolve();},100);
var p=d.promise();
while(++i<len){
p.then(fn[i]);
}
しかし、すべて同じ予期しない結果で、bはaの延期が解決される前に呼び出され、cはbの延期が解決される前に呼び出されます。
1.8より前のjQueryの場合、これは問題ですが、jQueryの新しいバージョンの場合、これはもう問題ではありません。
function test(){
var d = jQuery.Deferred(),
p=d.promise();
//You can chain jQuery promises using .then
p.then(a).then(b).then(c);
d.resolve();
}
test();
以下はjQuery1.7.2のデモです
jQuery <1.8は優れたWRTチェーンであり、.pipe
の代わりに.then
を使用するだけです。 1.8は単に.then
を.pipe
に変更しました。
補足:配列なしで使用する場合、promiseから始める必要はありません。 $.when({}).then(a).then(b)
はうまく機能します。 a
をwhen
の中に入れないようにする必要があるだけです。