我几乎同时在我的控制器上执行一个函数时出现了一些异步错误。每个控制器都会获取一些数据,并调用服务中的方法进行测试。该服务向控制器返回一个promise,操纵传入的数据,然后解析promise。服务的代码大纲如下所示:
<!-- language: lang-js -->
//Service that our controller can access
app.service("testing", function($timeout, $q) {
//Test function which takes a group, and returns a promise with the result
this.Test = function(resultsLocation, testList, testFunction) {
//promise we are returning
var deferred = $q.defer();
var i = 0;
//TestCallback loop
TestCallBack = function(testList) {
if (i < testList.length) {
//perform a test on one item of the list
testFunction(testList[i]).then(function() {
//push result back to controller
resultsLocation.push(testList[i].result);
i++;
//show result of that one item with scope update.
//also looks visually pleasing to see test come in
//one at a time
$timeout(function() {
TestCallBack(testList);
}, 100);
});
} else {
//we are done. Resolve promise
deferred.resolve("Done");
}
};
//initiate loop
TestCallBack(testList);
//return promise
return deferred.promise;
};
});//testing Service
然后我有一些大致如下的控制器:
<!-- language: lang-js -->
//Peripheral
app.controller("peripheral#", function($scope, testing) {
//self stuff
$scope.Title = "Peripheral#";
$scope.Summary = "";
$scope.Results = new Array();
//initial lin tests
var DiagnosticsList = [
//test1
//test2
//etc...
];
//Tests routine
$scope.Testing = function() {
//reset results
$scope.Results = new Array();
$scope.Summary = "Testing...";
//Do Tests
testing.Test($scope.Results, DiagnosticsList, CustomTestingFunction1).then(
function(result) {
$scope.Summary = "Testing...";
},
function(error) {
console.log("Error testing Peripheral1");
}
);
};
});
在html中按下按钮调用“测试”。问题是如果controller1调用“Testing”,然后controller2调用“Testing”,则promise将永远不会在controller1中解析。更糟糕的是,一些测试结果被推入控制器2的结果中。
也许我错过了一些东西,但我可以发誓我在某个地方读到一个服务将是它自己的实例当控制器拥有它。
无论如何,这是一个展示行为的傻瓜:https://plnkr.co/edit/fE5OD35LaXHWrhv0ohq2?p=preview
单独按“测试”是正常的,但如果在另一个控制器测试时按“测试”,则会出现奇怪的行为,例如值混淆,第一个控制器永远不会完成测试。
答案 0 :(得分:0)
问题是该服务将全局变量TestCallBack
分配给对本地匿名函数的引用。而是在服务功能范围内将其声明为命名的函数。
app.service("testing", function($timeout, $q) {
//Test function which takes a group, and returns a promise with the result
this.Test = function(resultsLocation, testList, testFunction) {
//promise we are returning
var deferred = $q.defer();
var i = 0;
//TestCallback loop
//DONT use global variable
//TestCallBack = function(testList) {
//INSTEAD use a named function
function TestCallBack(testlist) {
if (i < testList.length) {
所以只是澄清一下,将函数声明为var会将其置于全局范围内,即使在函数内声明也是如此?
错误是将值设置为未声明的变量。
在执行赋值时,为未声明的变量赋值会隐式地将其创建为全局变量(它将成为全局对象的属性)。声明和未声明变量之间的差异是:
声明的变量在声明它们的执行上下文中受到约束。未声明的变量总是全局的。
在执行任何代码之前创建声明的变量。在执行分配给它们的代码之前,不存在未声明的变量。
声明的变量是其执行上下文(函数或全局)的不可配置属性。未声明的变量是可配置的(例如可以删除)。
由于存在这三个差异,未能声明变量很可能会导致意外结果。因此,建议始终声明变量,无论它们是在函数还是全局范围内。在ECMAScript 5严格模式下,分配给未声明的变量会引发错误。 {{3 }}
在这种情况下,当第二次调用service.Test
函数时,全局值TestCallBack
被service.Test
第二个实例中对匿名函数的引用所取代。功能。匿名TestCallBack
函数引用service.Test
函数的闭包 1 。闭包是一种特殊的对象,它结合了两个东西:一个函数,以及创建该函数的环境。因此,第一个实例化安排的函数将i
和resultsLocation
切换到service.Test
函数的第二个实例的2。