在解决 angular 承诺时保留对调用对象的引用

Keep reference to the calling object when resolving an angular promise

问题

当解决承诺时,javascript 上下文更改为 Window # - 这意味着我无法引用正在解决承诺的对象,也无法使用或更改其任何变量。

如果我使用 that = this hack,我可以参考它,但问题是如果我有多个对象使用这个 hack,它们将共享相同的 window.that 变量并且它们会混淆的。

这是我为演示此问题而创建的一些示例代码:

app.js

var app = angular.module('myApp', []);
//Represents a service that makes call to the server. 
//Returns angular promises
app.service('MyService', function($q, $timeout){

    this.evenOrOdd = function(i){

        console.log("even or odd for: " + i);
        var deffered = $q.defer();

        $timeout(function(){    
                console.log("starting time out");
                if (parseInt(i)) {

                    if (i%2 === 1) deffered.resolve("Odd:" + i);
                    else deffered.resolve("Even" + i);                  
                }
                else deffered.reject("That's not an int!");
            }, 3000);

        return deffered.promise;

    };


});


//Represents some business object 
//We may want several of these
app.factory('MyFactory', function(MyService){

    return function() {

            //Some object specific variable
            this.rand = Math.random();

            console.log("creating new factory object with rand = " + this.rand);

            this.oddCheck = function(i){            
                var promise = MyService.evenOrOdd(i);

                that = this;        //the problem is here

                promise.then(function(value){               
                    console.log(that.rand + "|" + value);

                    }
                );  

                promise.catch(function(value){
                    console.log(that.rand + "|" + value);
                });

            };


    };

});


//Our controller, makes calls to update multiple objects at the same time
app.controller('MyController', function($scope, MyFactory) {

    $scope.factoryObject = new MyFactory();
    $scope.factoryObject2 = new MyFactory();

    $scope.myClick = function(){    

        $scope.factoryObject.oddCheck(10);
        $scope.factoryObject2.oddCheck(11);

    };


    }
);

index.html

<!DOCTYPE html>
<html>
<head>

<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js" type ="text/javascript"></script>
<script src = "app.js" type ="text/javascript"></script>

</head>
<body  ng-app="myApp" >

    <div ng-controller = "MyController">

        <button ng-click = "myClick()">Click me</button>

    </div>

</body>
</html>

当我们 运行 时,我们得到:

creating new factory object with rand = 0.10776704256566871
app.js (line 38)
creating new factory object with rand = 0.5952598424233105
app.js (line 38)
even or odd for: 10
app.js (line 8)
even or odd for: 11
app.js (line 8)
starting time out
app.js (line 12)
0.5952598424233105|Even10   //Rand is wrong
app.js (line 46)
starting time out
app.js (line 12)
0.5952598424233105|Odd:11
app.js (line 46)

在解决 promise 时,我还能如何跟踪对象的位置?

尝试 var that = this; 否则你使用的是一个一直被覆盖的全局变量 - 或者查看绑定 - 例如

this.oddCheck = function(i){            
    var promise = MyService.evenOrOdd(i);
    promise.then(function(value){               
        console.log(this.rand + "|" + value);
    }.bind(this));  

    promise.catch(function(value){
        console.log(this.rand + "|" + value);
    }.bind(this));

};

最后 - 上面的函数也可以这样写:

this.oddCheck = function(i){            
    MyService.evenOrOdd(i)
    .then(function(value){               
        console.log(this.rand + "|" + value);
    }.bind(this))
    .catch(function(value){
        console.log(this.rand + "|" + value);
    }.bind(this));
};

我更喜欢这样使用。你应该 return 反对。您可以在该对象内部引用自身。这是示例:http://jsbin.com/memaha/12/edit?js,console

您也可以使用 Ecmascript 6 箭头函数。它提供父上下文。.then(res => console.log(this.rand)//this will be outter function)