cover image by Carmella Fernando on Flickr, cropped by me
Promises are the new found love of JavaScript developers, but often I read things like "Aren't they just more complicated callbacks?!". So after all these posts about promises lateley, I thought about throwing in my 2 cent in the hope that it helps somebody to write better code.
1. Promises don't care about when you need their data
One really nice feature of promises that elevates them over callbacks is, they don't care when you add a callback with then
.
You can write code like that and it just works:
const wait = ms => new Promise(r => setTimeout(r, ms));
const waitTenMilliseconds = wait(10);
setTimeout(() =>
waitTenMilliseconds.then(() => console.log("Hello!"))
, 1000);
The first promise waitTenMilliseconds
will resolve before the timeout that adds the callback, but the callback will still be called.
Tip: Sometimes promise implementations differ on when to call you. Some put all your callbacks to the end of the event-loop, some call them right away if the promise is already resolved or calculated synchronously.
2. Promises flatten out other promises
Often you can tell right away that someone doesn't know this when reading their promise based code, but this is a really nice feature that lets you mix values you already have with those that need to be calculated or fetched asynchronously.
then
has monadic behaviour, it looks at what you return in the callback and if it's another promise it waits till it resolves, unpacks the value from it and puts it into the next callback. If it's just a regular value it puts it into the next callback right away.
Promise.resolve("ID_123")
.then(userId => fetch("/users/" + userId)) // returns a promise
.then(response => response.json()) // returns a promise
.then(json => `${json.firstName} ${json.lastName}`) // returns a string
.then(name => console.log(name)) // returns undefined
As I said, mixing is allowed too!
const myData = [
0,
123,
fetch("/number/456").text(),
fetch("/number/789").text(),
999
];
Promise.all(myData)
.then(numbers => console.log(numbers.join(", ")));
The myData
array contains values and promises. The static all
method of Promise
will look at every value, add it into a new array and wait for the promises to resolve before adding them. This allows the next then
callback to get an array of the same size, but with all promises replaced by their values after all promises in the array resolved.
3. Promises eat errors for breakfast
Most of the time you get a unhandled promise rejection error when something inside your promises fails, but more often than not you end up with something that doesn't throw anything and you're stuck with code that simply doesn't do anything, not even show an error. Sometimes because the promises a library returns haven't implemented the reject
call on an error.
This gets even worse with asynchronous functions, because you don't see the promises anymore. You put an async
before your function and all your errors are gone, because your function is now wrapped inside a promise and swallows your error.
So it is really important to check for errors with catch
on a promise or by using try-catch
in asynchronous functions.
Conclusion
Promises are a nice addition to JavaScript, but they don't come without a cost. I think they allow you to write your code more structured than with plain callbacks, but, like with every abstraction, you have to understand them or they will bite you.
50. Article
My new years resolution for 2017 was to write an article every week and I almost got it.
Sometimes I was sick or didn't want to write stuff, but your comments and likes kept me going.
Thank you!
Also, I want to thank the creators of dev.to who made it easy for a dev to write!
I'm seeing the MVPs in the dev space flocking to the platform one after another lately, so it will be interesting how the platform changes in 2018!
Top comments (9)
Let me just say: Thanks a million K! Your articles are really good and have been seriously helpful 🙌🏼. I hope you'll do another 50 in 2018!
That's always good to hear :)
It also helps myself to write, sometimes I find out that I'm not knowing as much as I thought :D
Congrats on the 50th 👏
Another thing that makes promises cool is how they race and fulfill completely.
PS: you have a minor typo in first snippet at
setTimoeut
🤓Thanks!
Yes, the other methods are nice too, but
all
is the one I used most often.PS: fixed the typo :D
I look forward to read more from you next year!
Great explanation. Will be waiting for your next one!
It's been like 2 years since I learned about promises. I love how compact and reliable they are for doing async things in a sequence. I'm a bit confused as to when to use resolve and what that means.
is a shortcut for