Backbone 点击事件回调中的奇怪索引问题
Weird index issue in Backbone click event callback
我有这段代码,它是独立和孤立的。我遇到的问题是索引我从 1 开始而不是从 0 开始。我不知道为什么会这样,而且似乎与我推入删除数组的闭包没有任何关系...但我不能确定,不知道问题出在哪里。
onClickResetAll: function (event) {
event.preventDefault();
var deletes = [];
Object.keys(collections).forEach(function (key) {
if (collections.hasOwnProperty(key)) {
var coll = collections[key];
for (var i = 0; i < coll.models.length; i++) {
deletes.push(function (callback) {
var index = i; //i starts at 1, not 0 !!!
coll.models[index].deleteModel(function (err, resp, x) {
console.log(err, resp, x);
if(err){
callback(err);
}
else{
callback(null,null);
}
});
});
}
}
});
async.parallel(deletes,function(err,results){
Backbone.Events.trigger('bootRouter', '+refreshCurrentPage');
});
}, //end of onClickResetAll callback function
//end
问题不在于 i
从 1 开始,问题在于 i
对于 deletes
中的每个函数都将是 coll.models.length
。为什么会这样?好吧,每个函数都共享相同的 i
并且 i
不会被评估,直到实际调用 deletes
中的函数。
解决方案是在 i
具有您想要的值时强制对其求值(即在构建回调函数时对 i
求值)。有多种解决方案,它们都是 "wrap it in a function to break the reference" 主题的变体:
使用带有回调函数的迭代器而不是普通的 for
循环:
coll.each(function(model, i) {
// `model` is the model from the collection, `i` is the loop index.
});
你可以在这里使用each
因为Backbonecollections have a bunch of Underscore functions built in.
将循环体包装在 SIF 中:
for(var i = 0; i < coll.models.length; ++i)
(function(i) {
//...
})(i);
使用单独的函数构建函数:
function make_deleter(coll, i) {
return function(callback) {
coll.models[i].deletedModel(function(err, resp, x) {
//...
}
}
}
//...
for(var i = 0; i < coll.models.length; ++i)
deletes.push(make_deleter(coll, i));
它们几乎都做同样的事情:在组合中添加一个额外的函数调用以强制 i
在循环的每次迭代中被评估(而不是仅仅被引用)。
在 Backbone 的情况下,1 可能是最自然的,你甚至不需要用那种方法麻烦 i
。
另一个解决方案是使用 async.each 或 async.eachSeries 而不是 async.parallel。使用前两个可以避免完全推送到函数数组。
我有这段代码,它是独立和孤立的。我遇到的问题是索引我从 1 开始而不是从 0 开始。我不知道为什么会这样,而且似乎与我推入删除数组的闭包没有任何关系...但我不能确定,不知道问题出在哪里。
onClickResetAll: function (event) {
event.preventDefault();
var deletes = [];
Object.keys(collections).forEach(function (key) {
if (collections.hasOwnProperty(key)) {
var coll = collections[key];
for (var i = 0; i < coll.models.length; i++) {
deletes.push(function (callback) {
var index = i; //i starts at 1, not 0 !!!
coll.models[index].deleteModel(function (err, resp, x) {
console.log(err, resp, x);
if(err){
callback(err);
}
else{
callback(null,null);
}
});
});
}
}
});
async.parallel(deletes,function(err,results){
Backbone.Events.trigger('bootRouter', '+refreshCurrentPage');
});
}, //end of onClickResetAll callback function
//end
问题不在于 i
从 1 开始,问题在于 i
对于 deletes
中的每个函数都将是 coll.models.length
。为什么会这样?好吧,每个函数都共享相同的 i
并且 i
不会被评估,直到实际调用 deletes
中的函数。
解决方案是在 i
具有您想要的值时强制对其求值(即在构建回调函数时对 i
求值)。有多种解决方案,它们都是 "wrap it in a function to break the reference" 主题的变体:
使用带有回调函数的迭代器而不是普通的
for
循环:coll.each(function(model, i) { // `model` is the model from the collection, `i` is the loop index. });
你可以在这里使用
each
因为Backbonecollections have a bunch of Underscore functions built in.将循环体包装在 SIF 中:
for(var i = 0; i < coll.models.length; ++i) (function(i) { //... })(i);
使用单独的函数构建函数:
function make_deleter(coll, i) { return function(callback) { coll.models[i].deletedModel(function(err, resp, x) { //... } } } //... for(var i = 0; i < coll.models.length; ++i) deletes.push(make_deleter(coll, i));
它们几乎都做同样的事情:在组合中添加一个额外的函数调用以强制 i
在循环的每次迭代中被评估(而不是仅仅被引用)。
在 Backbone 的情况下,1 可能是最自然的,你甚至不需要用那种方法麻烦 i
。
另一个解决方案是使用 async.each 或 async.eachSeries 而不是 async.parallel。使用前两个可以避免完全推送到函数数组。