I know this question is old, and the accepted answer's great, but there's so many followup questions I wanted to consolidate some answers, even if only a reference for myself.
$q.when returns a Promise object. To get the Promise's resolved value, use promise .then(callbackFunction)
syntax...
let i = 1;
$q.when(i).then(function(resolvedValue){
console.log(resolvedValue === i);
});
More on Promises here
Same behavior if passing anything except a Promise/"then-able", including integers, strings, arrays, objects, and even functions.
Here are some examples:
// an object...
let o = {name:'Nate'};
$q.when(o).then(function(resolvedValue){
console.log(resolvedValue === o);
});
//...an array...
let a = ['Nate'];
$q.when(a).then(function(resolvedValue){
console.log(resolvedValue === a);
});
If you pass a function without executing the function, it's just like passing any other object except a Promise; the resolvedValue will be equal to the function itself, regardless of the return value of the function.
let i = 1;
let f = function(){ return Promise.resolve(i); };
$q.when(f).then(function(resolvedValue){
// the resolvedValue is the *function* `f` itself!...
console.log(resolvedValue === f);
// the resolvedValue is NOT the function's return value, even if the function returns a Promise
console.log(resolvedValue !== i);
});
Calling the function first $q.when(func)
vs $q.when(func())
Just as @jrista says, if you have a function that returns a Promise, and you call that function before passing to $q.when
, then you're really just passing a Promise into $q.when
.
let i = 1;
let f = function(){ return i; };
$q.when(f); /* the resolved value will be the function `f` itself */
$q.when(f()); /* the resolved value will be based on the function `f`'s return value (the function `f` is no longer relevant, because you called it*/
$q.when(func)
vs $q.when(..).then(func)
Be careful not to confuse passing the function into the Promise/$q.when(f) (in which case the Promise's resolved value will be equal to the function):
let f = function(){ /*...*/ };
$q.when(f)
vs using the function in the .then()
(in which case the function will be executed and passed the resolved value of the Promise):
let f = function(){ /*...*/ };
$q.when(/*...*/).then(f);
What if I pass a Promise/"then-able"?
As the docs and the other answers say, passing a Promise object (or any "then-able") is special. Rather than resolving to the same Promise object you passed, $q.when
will resolve the the Promise's resolved value.
let i = 1;
let p = Promise.resolve(i);
$q.when(p).then(function(resolvedValue){
// the resolvedValue is *NOT* the promise `p` itself...
console.log(resolvedValue !== p);
// the resolvedValue **IS* the promise's *resolved* value:
console.log(resolvedValue === i);
});
Why use $q.when
?
As the docs say:
useful when you are dealing with an object that might or might not be a promise, or if the promise comes from a source that can't be trusted.
Consistent return types
Let's give an example of "might or might not be a promise"; maybe you cache the results of $http()
get request. Now you can have a function that returns the cached value, or returns an asynchronous $http()
request to get the value.
var cache = {};
var get_value_from_cache_or_$http_get = function (resource_id){
var cached_value = cache[resource_id];
if (cached_value){
// if you cached the value, you don't need to make another $http request...
// HOWEVER you still want to return a Promise/then-able,
// so the code calling your function `get_value_from_cache_or_$http_get`
// gets a consistent return type (i.e. something "then-able")
return $q.when(cached_value);
} else {
return $http.get(resource_id);
}
}
Now the function get_value_from_cache_or_$http_get
will always return a "then-able", regardless of whether it fetched something that was a promise (i.e. $http.get
), or might not be a promise (i.e. fetched from cache
, but wrapped in $q.when
)
$scope
updates in the UI
I think this part of the docs is especially important (maybe the most important reason that I use $q.when
)...
$q
is integrated with the $rootScope.Scope
Scope model observation mechanism in AngularJS, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI.
In other words, I find that when I get the resolved value of a normal Promise and assign to $scope
, I don't always see the change in the UI immediately (I must wait for the next $digest()
).
let p = Promise.resolve('update');
p.then(function(resolvedValue){ $scope.val = resolvedValue; })
If I wrap the promise in $q.when
, I see the change in UI as soon as the resolved value is assigned to $scope
let p = Promise.resolve('update');
$q.when(p).then(function(resolvedValue){ $scope.val = resolvedValue; })
$q.when
vs $q.resolve
Note these functions are the same $q.when === $q.resolve
, as the docs say:
[$q.resolve
is an] alias of when
to maintain naming consistency with ES6.