What's wrong with awaiting a promise chain?

I’m working on an Angular 6 application and I’ve been told the following is an anti-pattern:

await someFunction().then(result => {
    console.log(result);
});

I realize that it is pointless to await a promise chain. If someFunction() returns a promise, you don’t need a promise chain if you’re awaiting it. You can do this:

const result = await someFunction();
console.log(result);

But I’m being told awaiting a promise chain can cause bugs, or that it will break things in my code. If the first code snippet above does the same thing as the second snippet, what does it matter which one is used. What dangers does the first snippet introduce that the second one doesn’t?

Answers:

Answer

Under the hood, async/await is just promises.

That is, when you have some code that looks like:

const result = await myAsyncFunction();   
console.log(result): 

That's exactly the same as writing:

myAsyncFunction().then(data => {
   const result = data; 
   console.log(result); 
}); 

The reason then - that you shouldn't mix async/await and .then chains - is because it's confusing.

It's better to just pick one style, and stick to it.

And while you're picking one - you might as well pick async/await - it's more understandable.

Answer

I’m being told awaiting a promise chain will break things in my code.

Not necessarily, your two code snippets do indeed work the same (as long as someFunction() really returns a promise).

What does it matter which one is used. What dangers does the first snippet introduce that the second one doesn’t?

It's harder to understand and maintain, it's confusing to mix different styles. Confusion leads to bugs.

Consider that you would need to add another promise call at the location of the console.log() call, or even a conditional return from the function. Can you use await in the callback like elsewhere in the function, do you need to return the result from the then callback, is it even possible to return from the outer function? All these questions don't even come up in the first snippet. And while they can be easily answered for your toy example, it might not be as easy in real code with more complex and nested control flow.

So you should prefer the more concise and clean one. Stick to await for consistency, avoid then in async functions1.

1: Of course, there's always an exception to the rule. I would say that it's cleaner to use promise chaining for error handling in some cases where you would use catch or the second then callback.

Answer

If your then code returned a promise instead of calling console.log, your first example would await, but your second example would not.

When you use async/await, you will catch your rejects in try/catch blocks. Your code will be less nested and clearer.

Using then often results in more nesting, and harder to read code.

You can await anything, whether or not it returns a promise. Sometimes this future-proofs calling a method that may one day become async or just return a promise without declaring async.

The downsides are complexity, performance, and compatibility, all of which pale in comparison to the gains.

I find that if you rely on a function's return value after calling it, and it is or may eventually become asynchronous, decorate calling your functions with await to your heart's delight, whether or not it is current async or returns a promise.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.