JQuery Отложенные и обещающие для последовательного выполнения синхронных и асинхронных функций
Если я хочу, чтобы синхронные и асинхронные функции выполнялись в определенном порядке, я мог бы использовать jQuery-обещание, но он, похоже, не работает так, как я ожидаю, что он будет работать.
Функции a, b и c должны выполняться в том порядке, когда в deferred.resolve()
вызывается, я ожидаю, что функция b будет выполнена, но все функции выполняются немедленно независимо от того, вызывается ли это решение.
Вот код:
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
Для jQuery до 1.8 это проблема, но для новых версий 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();
DEMO
Ниже приведена демонстрация jQuery 1.7.2
DEMO
Ответ 2
jQuery < 1.8 - это отличная цепочка WRT, вы просто используете .pipe
вместо .then
. 1.8 просто изменил .then
на .pipe
.
Ответ 3
Sidenote: когда вы используете его без массива, вам не нужно начинать с обещания. $.when({}).then(a).then(b)
сделает трюк просто отлично. Вам нужно только убедиться, что вы не ставите a
внутри when
.