DEV Community

Cover image for Gotchas about async/await and Promises

Gotchas about async/await and Promises

Massimo Artizzu on November 18, 2017

JavaScript has always had an asynchronous nature. Most of the web's APIs were synchronous though, but things eventually changed also thanks to func...
Collapse
 
kayis profile image
K • Edited

I switch between async/await and plain promises often. I also mix await with .catch()

Some code gets simpler with await, especially when I need to mix results of multiple promises and following requests are based on the results of the last ones.

const user = await getUser();
const posts = await getPosts(user.id);
return posts.map(p => ({...p, author: user.name});

Some code gets simpler with plain promises, like parallelisation. When I need to retrieve the data of multiple views in one screen I often drop them off as promise and then the result into the views when they arrive.

this.setState({docsLoading: true, foldersLoading: true});
getDocs().then(docs => this.setState({docs, docsLoading: false}));
getFolders().then(folders => this.setState({folders, foldersLoading: false}));
Collapse
 
aghost7 profile image
Jonathan Boudreau • Edited
doSomething().then(data => {
  doStuff(data).then(result => {
    doOtherStuff(data, result).then(outcome => {
      showOutcome(outcome, result, data);
    });
  });
});

Instead of this you can do something like the following:

const concat = _.curry(_.concat, 2)
doSomething()
  .then(data => 
    doStuff(data).then(concat(data))
  .then([data, result] =>
    doOtherStuff(data, result).then(concat([data, result]))
  )
  .then([data, result, outcome] =>
    showOutcome(data, result, outcome)
  )
Collapse
 
kayis profile image
K

Or like this:

doSomething()
  .then(data => Promise.all([data, doStuff(data)]))
  .then(([data, result]) => Promise.all([data, result, doOtherStuff(data, result)]))
  .then(([data, result, outcome]) => showOutcome(data, result, outcome));

Clean and simple approach, but passing around of all the values is quite cumbersome.

Collapse
 
aghost7 profile image
Jonathan Boudreau

My main point was that you can still get a "flat" result when you have interdependent calls.

You can also pull this off with callbacks.

Collapse
 
kurtmilam profile image
Kurt Milam

The 'tip' from Cory House that you shared in this article is an anti pattern that should be avoided.

If the doSomething() and doSomethingElse() from your example both throw, you will get an unhandled exception warning - only the first exception will be caught. This can lead to hard-to-debug warnings.

Promise.all is the safe way to execute multiple async processes in parallel.

Collapse
 
wassano profile image
wassano

Very interesting! I'm not an expert in javascript and I have faced this callback hell sometimes.
I use the caolan/async module to solve this in nodejs and also for web pages, is there any problem I'm missing? Like loosing too much performance or other things?

Collapse
 
ben profile image
Ben Halpern

Nice post. I've had a bit of a modern JS phobia I'm just starting to shake and this helps.

Collapse
 
mangekalpesh profile image
Kalpesh Mange

This is an eye-opener. Also, my kittens like this post. ;) :)