Reputation: 11718
Can some one explain me how does $q.when
work in AngularJS?
I'm trying to analyse how $http
work and found this:
var promise = $q.when(config);
And here is config object from Chrome console:
Object {transformRequest: Array[1], transformResponse: Array[1], cache: Object, method: "GET", url: "/schedule/month_index.html"…}
cache: Object
headers: Object
method: "GET"
transformRequest: Array[1]
transformResponse: Array[1]
url: "/schedule/month_index.html"
__proto__: Object
What happens next? How this object get's resolved or rejected?
Upvotes: 105
Views: 77194
Reputation: 21094
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);
});
$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);
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);
});
$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.
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 UII 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 ofwhen
to maintain naming consistency with ES6.
Upvotes: 0
Reputation: 11391
Calling $q.when
takes a promise or any other type, if it is not a promise then it will wrap it in a promise and call resolve. If you pass a value to it then it is never going to be rejected.
From the docs:
Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise. This is 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.
Upvotes: 117