Skip to content

Instantly share code, notes, and snippets.

@pdswan
Last active December 15, 2015 00:09
Show Gist options
  • Save pdswan/5171174 to your computer and use it in GitHub Desktop.
Save pdswan/5171174 to your computer and use it in GitHub Desktop.
What's the proper way to wrap a possibly asynchronous function in an angular deferred? I have an external, callback based SDK which interacts with an http API. The first time I ask for resources, an http call is made. The second time the data is cached so the callback is called immediately. This is a simplified example.
var data
function possiblyAsync(callback) {
if (alreadyLoaded) {
callback(data)
} else {
asyncLoad(function(loadedData) {
data = loadedData
callback(data)
})
}
}
// results in digest already in progress
// when already loaded
function deferPossiblyAsync = function() {
var deferred = $q.defer()
possiblyAsync(function(data) {
$scope.$apply(function() {
deferred.resolve(data)
})
})
return deferred.promise
}
// works, but feels wrong
// referenced at
// http://stackoverflow.com/questions/12729122/prevent-error-digest-already-in-progress-when-calling-scope-apply
function deferPossiblyAsync = function() {
var deferred = $q.defer()
possiblyAsync(function(data) {
if ($scope.$$phase) {
deferred.resolve(data)
} else {
$scope.$apply(function() {
deferred.resolve(data)
})
}
})
return deferred.promise
}
// UPDATE:
// does NOT work in all cases. woops.
//
// works and is cleaner, but "makes no guarantees as to when expression will be run"
// http://docs.angularjs.org/api/ng.$rootScope.Scope#$evalAsync
function deferPossiblyAsync = function() {
var deferred = $q.defer()
possiblyAsync(function(data) {
$scope.$evalAsync(function() {
deferred.resolve(data)
})
})
return deferred.promise
}
@fabiankessler
Copy link

just run into this with 1.0.6, here's my stacktrace. can't reproduce it.

Error: $apply already in progress
at Error ()
at g (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:84:227)
at Object.e.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:88:362)
at e (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:94:424)
at o (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:98:3)
at XMLHttpRequest.s.onreadystatechange (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:99:131)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:99:195
at l (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:95:369)
at m (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:94:97)
at Function.m.(anonymous function) (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js:96:278) angular.min.js:62
(anonymous function) angular.min.js:62
(anonymous function) angular.min.js:52
e.$apply angular.min.js:88
e angular.min.js:94
o angular.min.js:98
s.onreadystatechange angular.min.js:99
(anonymous function) angular.min.js:99
l angular.min.js:95
m angular.min.js:94
m.(anonymous function) angular.min.js:96
ConversationCtrl.$scope.switchConversationTo ctrl.conversations.js:280
ConversationCtrl.$scope.switchConversation ctrl.conversations.js:277
(anonymous function) angular.min.js:72
(anonymous function) angular.min.js:143
e.$eval angular.min.js:88
e.$apply angular.min.js:88
(anonymous function) angular.min.js:143
x.event.dispatch jquery.js:4692
y.handle jquery.js:4376

and thesea re my lines 279 to 281:

$scope.switchConversationTo = function($scope, conversation) {
$http.get('/s/conversations/read/'+conversation.objectId).success(function(result) {
}

when i had this error, the application was broken. clicking the button that calls this function would bring the error each time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment