DEV Community

Cover image for 3 Facts About Promises
K
K

Posted on

3 Facts About Promises

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);

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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(", ")));

Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
ardennl profile image
Arden de Raaij

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!

Collapse
 
kayis profile image
K

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

Collapse
 
hom3chuk profile image
Eugene Chekan

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 🤓

Collapse
 
kayis profile image
K

Thanks!

Yes, the other methods are nice too, but all is the one I used most often.

PS: fixed the typo :D

Collapse
 
damcosset profile image
Damien Cosset

I look forward to read more from you next year!

Collapse
 
pchauhan13 profile image
Prashant Singh Chauhan

Great explanation. Will be waiting for your next one!

Collapse
 
jenc profile image
Jen Chan

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.

Collapse
 
kayis profile image
K
Promise.resolve(999)

is a shortcut for

new Promise(resolve => resolve(999))