Javascript 将延迟的数组传递给$.when()
下面是一个人为的例子: HTML: JavaScript:Javascript 将延迟的数组传递给$.when(),javascript,jquery,argument-passing,jquery-deferred,.when,Javascript,Jquery,Argument Passing,Jquery Deferred,.when,下面是一个人为的例子: HTML: JavaScript: function getSomeDeferredStuff() { var deferreds = []; var i = 1; for (i = 1; i <= 10; i++) { var count = i; deferreds.push( $.post('/echo/html/', { html: "<p>Tas
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>");
});
});
});
我要把一切都做完!在所有延迟任务完成后显示,但$.when似乎不知道如何处理延迟对象数组。全部完成!首先发生,因为数组不是延迟对象,所以jQuery继续并假设它刚刚完成
我知道可以将对象传递到函数中,如$。WhenFerred1、deferred2、…、deferredX,但不知道在我试图解决的实际问题中执行时会有多少个延迟对象。要将值数组传递给任何通常希望它们是单独参数的函数,请使用function.prototype.apply,因此,在这种情况下,您需要:
$.when.apply($, my_array).then( ___ );
看
在ES6中,您可以使用。。。相反:
在这两种情况下,由于您不太可能事先知道.then处理程序需要多少形式参数,因此该处理程序需要处理arguments数组以检索每个承诺的结果。您可以对数组应用when方法:
var arr = [ /* Deferred objects */ ];
$.when.apply($, arr);
以上解决方法谢谢!不要正确地解决返回提供给延迟解析方法的对象的问题,因为jQuery使用单个参数而不是数组调用done和fail回调。这意味着我们必须使用arguments伪数组来获取延迟数组返回的所有已解析/拒绝的对象,这很难看: $.when.apply$,deferreds.then函数{ var objects=arguments;//作为伪数组的已解析对象数组 ... }; 因为我们传递了一系列延迟,所以返回一系列结果会很好。如果能得到一个实际数组而不是伪数组,那么我们就可以使用array.sort之类的方法 以下是一个受when.js的when.all方法启发的解决方案,该方法解决了以下问题: //放在脚本环境中的某个地方 如果jQuery.when.all的类型==“未定义”{ jQuery.when.all=函数延迟{ 返回$.Deferredfunction def{ $.when.applyjQuery,deferreds.then //调用函数将接收长度为N的数组,其中N是 //传递给when.all的延迟对象已成功。该数组中的每个元素都将 //它本身是一个由3个对象组成的数组,对应于传递给jqXHR.done的参数: //数据,文本状态,jqXHR 作用{ var arrayThis,arrayArguments; 如果Array.isArraythis{ arrayThis=这个; arrayArguments=参数; } 否则{ arrayThis=[这个]; arrayArguments=[参数]; } def.resolveWitharrayThis[Array.prototype.slice.callarrayArguments]; }, //调用函数将接收长度为N的数组,其中N是 //传递给when.all的延迟对象失败。该数组中的每个元素都将 //它本身是一个由3个对象组成的数组,对应于传递给jqXHR.fail的参数: //jqXHR,textStatus,errorboorn 作用{ var arrayThis,arrayArguments; 如果Array.isArraythis{ arrayThis=这个; arrayArguments=参数; } 否则{ arrayThis=[这个]; arrayArguments=[参数]; } def.rejectWitharrayThis[Array.prototype.slice.CallArrayArrayGuments]; }; }; } } 现在,您只需传入一个延迟/承诺数组,并在回调中返回一个已解析/拒绝对象数组,如下所示:
$.when.all(deferreds).then(function(objects) {
console.log("Resolved objects:", objects);
});
如果您使用的是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:
作为一个简单的替代方案,它不需要$.when.apply或数组,您可以使用以下模式为多个并行承诺生成单个承诺:
promise = $.when(promise, anotherPromise);
e、 g
笔记:
在看到有人使用promise=promise.thennewpromise按顺序链接承诺后,我发现了这个问题
缺点是它会在幕后创建额外的promise对象,并且在最后传递的任何参数都不是很有用,因为它们嵌套在其他对象中。为了你想要的东西,虽然它很短很简单。
好处是它不需要阵列或阵列管理。
在调用多个并行AJAX调用时,有两个选项用于处理相应的响应 使用同步AJAX调用/一个接一个/不推荐 使用Promissions的数组,它接受Promissions及其回调。当所有Promissions都成功返回并带有相应的响应时,将调用done。 范例 functi 论资本性{ 返回$.ajax{ 网址:'https://restcountries.eu/rest/v1/capital/"资本,, 成功:功能响应{ }, 错误:functionresponse{ 控制台日志错误 } }; } $function{ var capitalCities=[‘德里’、‘北京’、‘华盛顿’、‘东京’、‘伦敦’]; $‘资本’。文本资本; 函数getCountryCapitals{//执行多个并行ajax请求 var承诺=[];
forvar i=0,l=capitalCities.length;i我想用$提出另一个方案。每个: 我们可能需要声明ajax函数,如:
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;
}
}
我们使用ajax创建要发送的函数数组的代码部分:
var arrayOfFn = [];
for (var i = 0; i < someDataArray.length; i++) {
var ajaxFnForArray = new ajaxFn(someDataArray[i]);
arrayOfFn.push(ajaxFnForArray);
}
如果您正在传输并且可以访问ES6,那么可以使用spread语法,该语法专门将对象的每个iterable项作为离散参数应用,就像$。需要时那样
$.when(...deferreds).done(() => {
// do stuff
});
我有一个非常类似的例子,我在一个each循环中发布,然后根据从ajax接收到的数字在一些字段中设置html标记。然后我需要对这些字段现在更新的值进行求和,并将其放在一个total字段中 因此,问题是我试图对所有数字进行求和,但异步ajax调用尚未返回任何数据。我需要在几个函数中完成此功能,以便能够重用代码。我的外部函数等待数据,然后再使用完全更新的DOM执行一些操作
// 1st
function Outer() {
var deferreds = GetAllData();
$.when.apply($, deferreds).done(function () {
// now you can do whatever you want with the updated page
});
}
// 2nd
function GetAllData() {
var deferreds = [];
$('.calculatedField').each(function (data) {
deferreds.push(GetIndividualData($(this)));
});
return deferreds;
}
// 3rd
function GetIndividualData(item) {
var def = new $.Deferred();
$.post('@Url.Action("GetData")', function (data) {
item.html(data.valueFromAjax);
def.resolve(data);
});
return def;
}
这真是太棒了。我很惊讶我没能通过谷歌找到这么简单的更改!那是因为它是一个通用方法,不特定于$。当-f.applyctx时,我的_数组将用这个==ctx调用f,并将参数设置为我的_数组的内容。@Alnitak:考虑到这个方法有多长时间,我有点不好意思不知道我现在一直在写JavaScript!FWIW,Eli在回答一个更早期的问题时,讨论了将$vs null作为第一个参数,其中的链接值得一读。不过,在这种特殊情况下,这并不重要。@Alnitak:是的,但是$的键入比null少,并且当$发生变化时,您是安全的。当实现发生变化时,这种情况不太可能发生,但是为什么不在默认情况下保持不变呢?我确实看到了这个问题,但我想,这个问题中所有额外的细节都让我的问题的答案飞到了我的头上。@adamjford,如果这能让你感觉更好的话,我发现你的问题更容易理解,首先是在我特定的谷歌搜索中找到了这个确切的问题。@帕特里奇:很高兴听到它帮助了你!这是一个很好的答案,但我不清楚这是如何应用于原始问题中的示例的。在查阅了链接问题后,很明显,行$.WhenFerreds.donefunction{应该简单地更改为$.when.apply$,deferreds.donefunction{.对吗?这完全不相关。@BenjaminGruenbaum怎么会这样?所有javascript promise库都共享一个类似的API,显示不同的实现没有什么错。我来到这个页面是为了寻找angular的答案,我怀疑许多其他用户会来到这个页面,而不一定是在只使用jquery的环境中。也就是说,因为jQuery的承诺不共享此API,所以这完全不适合作为堆栈溢出的答案-Angular也有类似的答案,您可以在那里询问。更不用说,您应该在这里映射,但很好。相关:为下面这个非常老的问题添加了一个新的、更简单的答案。您不需要使用数组或$.when.ap完全可以得到相同的结果。回滚问题主题,因为它太具体了,这不仅仅是一个AJAX问题如果我错了请纠正我,但是您的方法实际上是嵌套$.when$.when$.when…所以如果有10次迭代,您将递归地嵌套10个级别。这似乎不是非常并行,因为您必须等待每个级别l在返回子级的嵌套承诺之前返回它自己的承诺-我认为接受答案中的数组方法更干净,因为它使用了$.when方法中内置的灵活参数行为。@AnthonyMcLin:这是为了提供一种更简单的编码替代方法,而不是更好的性能,这在大多数as中是可以忽略的ync编码,就像链接一样,然后以类似的方式调用。使用$.when时的行为是并行的,而不是链接的。请尝试一下,然后扔掉一个有用的替代方法,因为它确实有效:@Alnitak:Horses for courses。你当然有权发表意见,但你自己显然没有使用过。我个人的意见是bas这项技术的实际用途是非常有用的,所以为什么要从工具箱中扔掉一个工具呢?它是基于一些夸张的东西,比如警告,什么都不能解决——它消除了数组处理,简化了不需要返回值的并行承诺的链接,正如您应该知道的,在第不管怎样,所有的案件都在处理中。这个答案应该是否定的:Hi@Gon
生态编码。请不要在你的回答中添加投票评论?这适合于评论,但在其他方面,噪音会分散人们对其他好内容的注意力。谢谢。@halfer:我不再发帖了,但我对任何原创作品的无知感到恼火。现在我对自己保留所有的新想法:你的答案反应过激,你对问题标题的编辑也是如此。OP已经知道如何进行AJAX调用并获取延迟对象数组。问题的唯一一点是如何将该数组传递给$。when。我认为如果有可用的选项,用示例详细解释会更好。为此,我认为没有必要进行向下投票。向下投票是针对1的。甚至建议同步,尽管建议不要使用2。示例中的劣质代码包括。。。在阵列中?!1.同意,不应该推荐2.不同意-为了。。。在中是可以的,因为数组只包含那些不需要额外属性的属性。thanx anywaysre:2-问题是它可能会被其他无法保证的人复制,或者愚蠢到添加到Array.prototype。无论如何,对于非性能关键代码,最好使用.map而不是for/push循环,例如var promises=capitalCities.mapajaxRequest;$。when.apply$,promises.thenfillCountryCapitals-完成任务。代码中存在一个小问题,当数组中只有一个元素时,results数组只返回该结果,而不是一个包含单个元素的数组,这将破坏需要数组的代码。要修复此问题,请使用此函数var toArray=函数args{return deferreds.length>1?$.makeArrayargs:[args];}而不是Array.prototype.slice.call。
var arrayOfFn = [];
for (var i = 0; i < someDataArray.length; i++) {
var ajaxFnForArray = new ajaxFn(someDataArray[i]);
arrayOfFn.push(ajaxFnForArray);
}
$.when(
$.each(arrayOfFn, function(index, value) {
value.call()
})
).then(function() {
alert("Cheer!");
}
)
$.when(...deferreds).done(() => {
// do stuff
});
// 1st
function Outer() {
var deferreds = GetAllData();
$.when.apply($, deferreds).done(function () {
// now you can do whatever you want with the updated page
});
}
// 2nd
function GetAllData() {
var deferreds = [];
$('.calculatedField').each(function (data) {
deferreds.push(GetIndividualData($(this)));
});
return deferreds;
}
// 3rd
function GetIndividualData(item) {
var def = new $.Deferred();
$.post('@Url.Action("GetData")', function (data) {
item.html(data.valueFromAjax);
def.resolve(data);
});
return def;
}