How to Check Whether an Angular $q promise Is Resolved

AngularjsPromiseQ

Angularjs Problem Overview


I understand that typically one would just attach continuation code with a then() call and chain behaviour when using promises.

However, I want to kick off a promise-wrapped asynchronous call and then separately kick off a 3-second $timeout() so I can take a UI action, ONLY IF the original promise has not yet completed. (I anticipate that this would only happen on slow connections, mobile devices on 3G, etc.)

Given a promise, can I check whether it's complete or not without blocking or waiting?

Angularjs Solutions


Solution 1 - Angularjs

I guess this was added in a recent version of Angular but there seems to be now an $$state object on the promise:

 var deferred = $q.defer();
 console.log(deferred.promise.$$state.status); // 0
 deferred.resolve();
 console.log(deferred.promise.$$state.status); //1 

As noted in the comments this is not recommended as it might break when upgrading your Angular version.

Solution 2 - Angularjs

I think your best option as is, (without modifying the Angular source and submitting a pull request) is to keep a local flag for if the promise has been resolved. Reset it every time you setup the promise you're interested in and mark it as complete in the then() for the original promise. In the $timeout then() check the flag to know if the original promise has resolved yet or not.

Something like this:

var promiseCompleted = false;
promise.then(function(){promiseCompleted=true;})
$timeout(...).then(function(){if(!promiseCompleted)doStuff()})

Kris Kowal's implementation includes other methods for checking the state of the promise but it appears Angular's implementation of $q unfortunately doesn't include these.

Solution 3 - Angularjs

It doesn't seem to be possible, as @shaunhusain already mentioned. But maybe it's not necessary:

// shows stuff from 3s ahead to promise completetion, 
// or does and undoes it in one step if promise completes before
$q.all(promise, $timeout(doStuff, 3000)).then(undoStuff);

or maybe better:

var tooSlow = $timeout(doStuff, 3000);
promise.always(tooSlow.cancel);

Solution 4 - Angularjs

I have had a similar problem where I need to check if a promise has returned. Because AngularJS's $watch function will register a change while rendering the page even if both new and old values are undefined, I have to check to see if there is any data worth storing in my external model.

It is definitely a hack but I do this:

$scope.$watch('userSelection', function() {
  if(promiseObject.hasOwnProperty("$$v"){
    userExportableState.selection = $scope.userSelection;
  }
};

I know that $$v is an internal variable used by AngularJS, but it has been quite reliable as an indicator of a resolved promise for us. Who knows what will happen when we upgrade to AngularJS 1.2 :-/ I don't see any mention of improvements to $q in the 1.2 docs but perhaps someone will write a replacement service with a better feature set closer to Q.

Solution 5 - Angularjs

I don't know your exact scenario but it is more typical to put a timeout in place immediately after making the asynchronous call (and generating the promise).

Providing the setTimeout() statement is in the same event thread as the asynchronous call, you needn't worry about the possibility of a race effect. As javascript is strictly single threaded, the promise's .then() callbacks are guaranteed to fire in a later event thread.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionblasterView Question on Stackoverflow
Solution 1 - AngularjsparliamentView Answer on Stackoverflow
Solution 2 - AngularjsshaunhusainView Answer on Stackoverflow
Solution 3 - AngularjsBergiView Answer on Stackoverflow
Solution 4 - AngularjsPatchCRView Answer on Stackoverflow
Solution 5 - AngularjsBeetroot-BeetrootView Answer on Stackoverflow