Skip to main content
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Igor Mazor
Ben Nadel at CF Summit West 2024 (Las Vegas) with: Igor Mazor

$q.when() Is The Missing $q.resolve() Method In AngularJS

By
Published in Comments (16)

In AngularJS, the $q services has a top-level method, $q.reject(), which will create a promise that is immediately rejected with the given value. Ever since I saw this method, I have always wondered where the "resolve" equivalent was? If there's a $q.reject(), why not a $q.resolve()? Well, it turns out there is. Thanks to a mental-block, I never quite made the connection; but, $q.when() is the "missing" $q.resolve() method.

Run this demo in my JavaScript Demos project on GitHub.

The $q.when() method doesn't just create a promise that is immediately resolved; rather, it normalizes a value that may or may not be a "thenable" object. If the given value is a promise, $q.when() will properly chain off of it. If the given value is not a promise, $q.when() will create promise resolved with the given value.

To see this in action, I've put together a tiny demo that showcases the "simple" case of $q.reject() and $q.when() to create immediately rejected and resolved promises, respectively:

<!doctype html>
<html ng-app="Demo">
<head>
	<meta charset="utf-8" />

	<title>
		$q.when() Is The Missing $q.resolve() Method In AngularJS
	</title>
</head>
<body ng-controller="AppController">

	<h1>
		$q.when() Is The Missing $q.resolve() Method In AngularJS
	</h1>


	<!-- Load scripts. -->
	<script type="text/javascript" src="../../vendor/angularjs/angular-1.2.26.min.js"></script>
	<script type="text/javascript">

		// Create an application module for our demo.
		var app = angular.module( "Demo", [] );


		// -------------------------------------------------- //
		// -------------------------------------------------- //


		// I control the root of the application.
		app.controller(
			"AppController",
			function( $scope, $q ) {

				// The $q.reject() method creates a promise that is immediately rejected
				// with the given reason.
				$q.reject( "meh" ).catch(
					function handleReject( reason ) {

						console.log( "Rejected with reason:", reason );

					}
				);

				// The $q.when() method creates a promise that is immediately resolved
				// with the given value.
				// --
				// NOTE: If the given value is already a promise then it will be properly
				// chained (and routed) by the resultant promise.
				$q.when( "woot!" ).then(
					function handleResolve( value ) {

						console.log( "Resolved with value:", value );

					}
				);

			}
		);

	</script>

</body>
</html>

When we run this code, we get the following console output:

Rejected with reason: meh
Resolved with value: woot!

As you can see, each method returned a promise. The $q.reject() promise was rejected and the $q.when() promise was resolved.

Want to use code from this post? Check out the license.

Reader Comments

1 Comments

You are not alone!
It took me a lot of time to figure out the best way to use $q, specially inside services.
Before $q.when() and $q.reject() I was returning some silly responses into service methods =/

15,880 Comments

@Darlan,

Promises are generally hard to wrap your head around. And, even when you start using them, I find that I often forget how to use them properly. Every few months, I find it helpful to review this blog post on promise anti-patterns and how to avoid them:

http://taoofcode.net/promise-anti-patterns/

Some really good stuff there!

2 Comments

I thought the same thing when I first started using promises. In fact I went as far as writing $q.noop before discovering $q.when.
$q.noop = function () {
var deferred = $q.defer();
deferred.resolve();
return deferred.promise;
};

I do have one gripe about $q.when though. $q.when(myFunc) will resolve immediately myFunc. Although I think this is the clearest and cleanest API, it's not the most useful for me. Instead I prefer $q.whenFn(myFunc) which invokes and resolves the return from myFunc. $q.whenFn has proven really useful for implementing lazy loading in my APIs! I wrote about $q.whenFn here: http://www.codeducky.org/anqwhenfn/

1 Comments

@Steven,

There is actually no need in such noop() which doesn't accept any arguments since there is $q.resolve (not it's a property) which serves this purpose.

3 Comments

I love the documentation for $q.when:

"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."

...specifically that last part

What exactly does this mean? If you're using a promise from an external library that uses setTimeout - would this be an example of a promise that "can't be trusted"? Or is it more that you can't trust if it's a promise or a value?

15,880 Comments

@Jordan,

That's a really good question! One guess could be that it has to do with the way $q integrates with the $digest lifecycle. If you create a promise with $q, AngularJS will automatically trigger a $digest whenever the promise is exercised, either with reject, resolve, or notify. If, however, you get a promise from a non-AngularJS source, then you don't have that digest-integration. Using $q.when() to wrap an "untrusted" promise would be able to bridge the gap and make sure that the $digest cycle is triggered when the original promise returns with a value.

But that is just a guess on my part - it's actually something that I'd like to try to play with.

3 Comments

@Ben,

Yes - exactly what I was thinking!

A good use case for this is if, for instance, you really want to use an external promise library - you want to avoid the "Forgotten Promise" anti-pattern, but the library gives you a way to declare a timeout so you can ensure your call is not forgotten.

Anyways I had a look at the code and it doesn't appear that it makes a difference whether you decide to manually create the promise via $q.defer() or use $q.when(). $q.when() appears to just be a convenience method so you don't have to write extra code:

var when = function(value, callback, errback, progressBack) {
var result = new Deferred();
result.resolve(value);
return result.promise.then(callback, errback, progressBack);
};

..and so I don't think the $digest cycle should be handled any differently.

Also, just thought I would share this fun post on Angular promises: http://andyshora.com/promises-angularjs-explained-as-cartoon.html

15,880 Comments

@Jordan,

I just put together a follow-up exploration of this "can't be trusted" concept:

www.bennadel.com/blog/2835-normalizing-untrusted-deferred-promise-values-for-the-digest-lifecycle-in-angularjs.htm

If you watch the video, you will see that using the raw jQuery Deferred value will not trigger a digest; but, once it is wrapped in $q.when(), the $digest is successfully triggered.

And yes, I believe that you are wright - the .when() method is for convenience.

1 Comments

Thanks for this great short info video. I really wish they'd called it resolve and not when. When is conditional, resolve would just be that... resolve it. *sigh*

1 Comments

Ben, thanks for pointing this out! The angular documentation is very sparse about this and I would not have drawn the same conclusion.

Just solved an immediate problem I was facing.

Cheers

Jürgen

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel