具有一个服务的AngularJS多个控制器:异步错误

时间:2016-09-02 22:49:41

标签: javascript angularjs asynchronous

我几乎同时在我的控制器上执行一个函数时出现了一些异步错误。每个控制器都会获取一些数据,并调用服务中的方法进行测试。该服务向控制器返回一个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

单独按“测试”是正常的,但如果在另一个控制器测试时按“测试”,则会出现奇怪的行为,例如值混淆,第一个控制器永远不会完成测试。

1 个答案:

答案 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) {

DEMO on PLNKR

  

所以只是澄清一下,将函数声明为var会将其置于全局范围内,即使在函数内声明也是如此?

错误是将值设置为未声明的变量。

在执行赋值时,为未声明的变量赋值会隐式地将其创建为全局变量(它将成为全局对象的属性)。声明和未声明变量之间的差异是:

  1. 声明的变量在声明它们的执行上下文中受到约束。未声明的变量总是全局的。

  2. 在执行任何代码之前创建声明的变量。在执行分配给它们的代码之前,不存在未声明的变量。

  3. 声明的变量是其执行上下文(函数或全局)的不可配置属性。未声明的变量是可配置的(例如可以删除)。

  4. 由于存在这三个差异,未能声明变量很可能会导致意外结果。因此,建议始终声明变量,无论它们是在函数还是全局范围内。在ECMAScript 5严格模式下,分配给未声明的变量会引发错误。 {{3 }}

    在这种情况下,当第二次调用service.Test函数时,全局值TestCallBackservice.Test第二个实例中对匿名函数的引用所取代。功能。匿名TestCallBack函数引用service.Test函数的闭包 1 。闭包是一种特殊的对象,它结合了两个东西:一个函数,以及创建该函数的环境。因此,第一个实例化安排的函数将iresultsLocation切换到service.Test函数的第二个实例的2