假设我有一个站点,它通过对服务的HTTP调用保存电话号码,并且该服务返回电话号码条目的新ID,以绑定到页面上的电话号码。
在这种情况下,电话存储在一个名为"电话"的数组中,datacontext.phones.updateData 将电话发送到 $ 内的服务器。Deferred([service call logic]).promise();
uploadTelephones = function (deffered) {
for (var i = 0; i < telephones.length; i++){
deffered.push(datacontext.telephones.updateData(telephones[i], {
success: function (response) {
telephones[i].telephoneId = response;
},
error: function () {
logger.error('Stuff errored');
}
}));
}
}
现在,如果我打电话:
function(){
var deferreds = [];
uploadTelephones(deferreds);
$.when.apply($, deferreds)
.then(function () {
editing(false);
complete();
},
function () {
complete();
});
}
奇怪的事情发生了。所有电话都发送回服务并保存。当 uploadPhoness 方法中的"成功"回调以新 id 作为"响应"调用时,无论查询涉及哪个电话,i 的值始终是 phones.length+1 和
行telephones[i].telephoneId = response;
抛出错误,因为电话 [i] 不存在。
谁能告诉我如何在成功回调中保留 i 的个人值?
所有闭包(在本地范围内捕获变量的匿名函数)都引用相同的索引变量,该变量在循环执行后的值为 telephones.length
。 您需要为每次通过for
循环创建一个不同的变量,在创建实例中保存i
的值以供以后使用。
要创建一个新的不同变量,最简单的方法是创建一个匿名函数,其中包含用于捕获循环中特定位置的值并立即执行它的代码。
要么这个:
for (var i = 0; i < telephones.length; i++)
{
(function () {
var saved = i;
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})();
}
或者这个:
for (var i = 0; i < telephones.length; i++)
{
(function (saved) {
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})(i);
}
应该工作。
不过,这有点丑陋。 由于您已经在经历一遍又一遍地执行匿名函数的过程,如果您希望您的代码更简洁一点,您可能需要查看 Array.forEach 并使用传入的任何参数,或者只使用 jQuery.each,就像您已经在使用 jQuery 一样。