Identifying the Issue
One issue arises when resolving promises in Javascript: the context switches to Window #
. This means that referring back to the object resolving the promise becomes tricky because I can't access or modify its variables.
The common workaround is using the that = this
hack, but a drawback of this approach is that if multiple objects use this hack, they end up sharing the same window.that
variable and confusion ensues.
Below is a snippet of code I have put together to showcase this problem:
app.js
var app = angular.module('myApp', []);
//Represents a service making server calls
//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
//Multiple instances may be needed
app.factory('MyFactory', function(MyService){
return function() {
//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; //issue here
promise.then(function(value){
console.log(that.rand + "|" + value);
}
);
promise.catch(function(value){
console.log(that.rand + "|" + value);
});
};
};
});
//Controller handling updates on multiple objects simultaneously
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>
Running the code produces the following output:
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 //Incorrect Rand
app.js (line 46)
starting time out
app.js (line 12)
0.5952598424233105|Odd:11
app.js (line 46)
Are there alternative methods to keep track of the object's location when promises are resolved?