这里有一个关于正在发生的事情的人为例子:http://jsfiddle.net/adamjford/YNGcm/20/
HTML:
<a href="#">Click me!</a>
<div></div>
JavaScript:
function getSomeDeferredStuff() {
var deferreds = [];
var i = 1;
for (i = 1; i <= 10; i++) {
var count = i;
deferreds.push(
$.post('/echo/html/', {
html: "<p>Task #" + count + " complete.",
delay: count
}).success(function(data) {
$("div").append(data);
}));
}
return deferreds;
}
$(function() {
$("a").click(function() {
var deferreds = getSomeDeferredStuff();
$.when(deferreds).done(function() {
$("div").append("<p>All done!</p>");
});
});
});
我希望在所有延迟任务完成后显示“All done!”,但$.when()似乎不知道如何处理延迟对象数组。“All done!”首先发生,因为数组不是Deferred对象,因此jQuery继续执行并假定它已经完成。
我知道可以将对象传递到函数中,比如$。当(deferred1, deferred2,…, deferredX),但在我试图解决的实际问题中,不知道执行时会有多少个Deferred对象。
作为一种简单的替代方法,它不需要$.when。Apply或数组,你可以使用下面的模式为多个并行promise生成一个promise:
promise = $.when(promise, anotherPromise);
e.g.
function GetSomeDeferredStuff() {
// Start with an empty resolved promise (or undefined does the same!)
var promise;
var i = 1;
for (i = 1; i <= 5; i++) {
var count = i;
promise = $.when(promise,
$.ajax({
type: "POST",
url: '/echo/html/',
data: {
html: "<p>Task #" + count + " complete.",
delay: count / 2
},
success: function (data) {
$("div").append(data);
}
}));
}
return promise;
}
$(function () {
$("a").click(function () {
var promise = GetSomeDeferredStuff();
promise.then(function () {
$("div").append("<p>All done!</p>");
});
});
});
注:
我是在看到有人用promise = promise按顺序串起承诺后才明白这一点的。then(newpromise)
缺点是它在幕后创建了额外的承诺对象,并且在最后传递的任何参数都不是很有用(因为它们嵌套在额外的对象中)。对于你想要的东西,它是简短而简单的。
优点是它不需要数组或数组管理。
要将值数组传递给任何通常希望它们是单独参数的函数,请使用function .prototype。应用,所以在这种情况下,你需要:
$.when.apply($, my_array).then( ___ );
参见http://jsfiddle.net/YNGcm/21/
在ES6中,你可以使用…展开运算符改为:
$.when(...my_array).then( ___ );
在这两种情况下,由于您不太可能事先知道.then处理程序需要多少正式形参,因此该处理程序需要处理参数数组以检索每个promise的结果。
如果你正在使用angularJS或Q promise库的一些变体,那么你有一个.all()方法来解决这个确切的问题。
var savePromises = [];
angular.forEach(models, function(model){
savePromises.push(
model.saveToServer()
)
});
$q.all(savePromises).then(
function success(results){...},
function failed(results){...}
);
详见完整API:
https://github.com/kriskowal/q/wiki/API-Reference#promiseall
https://docs.angularjs.org/api/ng/service/美元问
我想建议使用$.each的另一个方法:
We may to declare ajax function like:
function ajaxFn(someData) {
this.someData = someData;
var that = this;
return function () {
var promise = $.Deferred();
$.ajax({
method: "POST",
url: "url",
data: that.someData,
success: function(data) {
promise.resolve(data);
},
error: function(data) {
promise.reject(data);
}
})
return promise;
}
}
Part of code where we creating array of functions with ajax to send:
var arrayOfFn = [];
for (var i = 0; i < someDataArray.length; i++) {
var ajaxFnForArray = new ajaxFn(someDataArray[i]);
arrayOfFn.push(ajaxFnForArray);
}
And calling functions with sending ajax:
$.when(
$.each(arrayOfFn, function(index, value) {
value.call()
})
).then(function() {
alert("Cheer!");
}
)
作为一种简单的替代方法,它不需要$.when。Apply或数组,你可以使用下面的模式为多个并行promise生成一个promise:
promise = $.when(promise, anotherPromise);
e.g.
function GetSomeDeferredStuff() {
// Start with an empty resolved promise (or undefined does the same!)
var promise;
var i = 1;
for (i = 1; i <= 5; i++) {
var count = i;
promise = $.when(promise,
$.ajax({
type: "POST",
url: '/echo/html/',
data: {
html: "<p>Task #" + count + " complete.",
delay: count / 2
},
success: function (data) {
$("div").append(data);
}
}));
}
return promise;
}
$(function () {
$("a").click(function () {
var promise = GetSomeDeferredStuff();
promise.then(function () {
$("div").append("<p>All done!</p>");
});
});
});
注:
我是在看到有人用promise = promise按顺序串起承诺后才明白这一点的。then(newpromise)
缺点是它在幕后创建了额外的承诺对象,并且在最后传递的任何参数都不是很有用(因为它们嵌套在额外的对象中)。对于你想要的东西,它是简短而简单的。
优点是它不需要数组或数组管理。