我想用angular构建一个承诺链来应用一组查询:
for(variableIndex in _editableVariable.values) {
var v = _editableVariable.values[variableIndex];
if(v.value != v.old_value) {
console.log('v', v);
var newVariableRes = new VariableValueRes(v);
if(v.old_value == undefined) {
p.then(function() {
console.log('B', newVariableRes);
return newVariableRes.$save().$promise;
});
} else {
console.log('Try update: ', v);
p.then(function() {
console.log('C', newVariableRes);
return newVariableRes.$update().$promise;
});
}
}
}
我的问题是当我显示console.log('v',v)
时,我得到了不同变量的不同value
。当我在承诺中并显示console.log('B', newVariableRes)
时,newVariableRes
的内容是最新变量的value
。
输出示例:
v
Object {value: "1", old_value: undefined, platform: "/api/v1/platform/1", product_variable: "/api/v1/product_var/2"}
v
Object {value: "2", old_value: undefined, platform: "/api/v1/platform/2", product_variable: "/api/v1/product_var/2"}
v
Object {value: "3", old_value: "", id: 7, platform: "/api/v1/platform/3", product_variable: "/api/v1/product_var/2"}
B
Resource {value: "3", old_value: "", id: 7, platform: "/api/v1/platform/3", product_variable: "/api/v1/product_var/2"…}
B
Resource {value: "3", old_value: "", id: 7, platform: "/api/v1/platform/3", product_variable: "/api/v1/product_var/2"…}
C
Resource {value: "3", old_value: "", id: 7, platform: "/api/v1/platform/3", product_variable: "/api/v1/product_var/2"…}
由于我是javascript的新手,我认为v
是对值的引用。因此,VariableValueRes
采用了这个参考。当我更改v
的指向引用时,这应该不会改变VariableValueRes
的内容。
我的误会在哪里?
我认为问题是JS只有全局或函数作用域。因此,您的v
和newVariableRes
变量(在 for 循环中声明)被视为与声明为周围函数的顶部相同。
循环的每次迭代,v
的值都会立即更新并记录,显示预期看到的值。但是,当您的 promise 回调执行时,循环已经完成,因此v
,newVariableRes
将保存其中的最后一个值。
这些回调通过闭包引用newVariableRes
,这意味着外部函数可以完成,内部函数(您的回调)仍然使用外部作用域中此变量的值,而不是使用创建函数时存在的任何值。
这是在JS代码中看到的一个非常常见的错误,通常解决方案是通过将其放入新的函数作用域来修复变量,如下所示
p.then((function(nvr) {
return function() {
console.log('B', nvr);
return nvr.$save().$promise;
};
})(newVariableRes));
通过这种方式,我们创建一个函数,将其作为参数提供给我们的变量。由于我们不会在函数中更改此参数,因此我们的回调可以通过闭包使用它并确保它不会更改。
一种更简单的方法,因为您已经在使用 angular,是用 angular.forEach
替换您的 for 循环,这将以与 v
完全相同的方式解决此问题。现在您知道v
回调中最初期望的,您可以在这些回调中创建new VariableValueRes(v)
,而不必担心newVariableRes
指向什么(因为您不会使用它)。