Using promises is tricky at first. Every newcomer to Angular will be flustered about them. It’s super easy to get lost at first between all the different nitpicks: promise chaining,
$http’s special promises, the asynchronous nature of it all, etc.
One of the first questions you tackle starting to learn promises is when, if at all, should you use
$q.defer() quite often when I first started with Angular. You know how much of that original code actually needed to use
defer()? About none at all.
I realized that there was almost no reason to use
defer() to create my own promises. It’s just cumbersome and error prone.
And guess what? I think that nearly everyone that uses it does it unnecessarily.
Real examples from GitHub
First, a disclaimer: this isn’t some sort of shaming. I used to write lots of code just like this. I want to show how common this problem is with real code and no handwaving.
I opened GitHub’s code search and started looking for people using
$q.defer(). In the first 3 pages of results I saw about 2 actual valid use cases. Yeeeep.
You don’t need defer to create a simple-valued promise
Let’s take a look at this case:
1 2 3 4
It’s easy to see the author just wanted to create a promise with some hard-coded value. Those 4 lines? They can just be rewritten as:
You don’t need defer to change the value of a promise
1 2 3 4 5
This successfully creates a promise that you can call with
.then() and receive as a value the actual response body. But, through the magic of promise chaining you can simplify this:
1 2 3
Promise chaining is a bit complicated, but the gist is this: inside a promise’s
.then() whatever you
return will be passed along to the next
.then() along the chain.
This means that in our example above we’re returning a regular promise whose
.then() will pass
response.data – sweet!
Sometimes you don’t need to do anything at all
Just about anything asynchronous is already a promise in Angular. Take a look at this:
1 2 3 4 5
The author wanted to return a promise that would get resolved once 5 seconds have passed. But guess what?
$timeout already returns a promise that does just that, allowing us to write this:
When should you use defer?
Basically, the main reason is:
You’re converting a callback API to be promise-based: For example, if you wrap a jQuery plugin to work in Angular. Callbacks are not as fun as promises. To kickstart the promise chain and convert callbacks you have the create the first promise.
I’ve written about actually creating promises here.
“Maintaining AngularJS feels like Cobol 🤷…”
You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?
It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.
Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.