Reader small image

You're reading from  Node.js Design Patterns - Third Edition

Product typeBook
Published inJul 2020
Reading LevelBeginner
PublisherPackt
ISBN-139781839214110
Edition3rd Edition
Languages
Tools
Right arrow
Authors (2):
Mario Casciaro
Mario Casciaro
author image
Mario Casciaro

Mario Casciaro is a software engineer and entrepreneur, passionate about technology, science and open source knowledge. Mario graduated with a master's degree in software engineering and started his professional career at IBM where he worked for several years on different enterprise products such as Tivoli Endpoint Manager, Cognos Insight, and SalesConnect. Next, he moved to D4H Technologies, a growing SaaS company, to lead the development of a new bleeding-edge product for managing emergency operations in real time. Currently, Mario is the co-founder and CEO of Sponsorama.com, a platform to help online projects raise funds through corporate sponsorship. Mario is also the author of the first edition of Node.js Design Patterns.
Read more about Mario Casciaro

Luciano Mammino
Luciano Mammino
author image
Luciano Mammino

Luciano Mammino is a software engineer born in 1987, the same year that the Nintendo released Super Mario Bros in Europe, which by chance is his favorite video-game. He started coding at the age of 12 using his father's old Intel 386, provided only with the DOS operating system and the qBasic interpreter. After a master's degree in computer science he developed his programming skills mostly as a web developer working mainly as freelancer for companies and startups all around Italy. After a start-up parenthesis of 3 years as CTO and co-founder of Sbaam.com in Italy and in Ireland, he decided to relocate in Dublin to work as senior PHP engineer at Smartbox. He loves developing open source libraries and working with frameworks such as Symfony and Express. He is convinced that the JavaScript fame is still at the very beginning and that this technology will have a huge impact in the future of most of the web-and mobile-related technologies. For this reason, he spends most of his free time improving his knowledge of JavaScript and playing with Node.js.
Read more about Luciano Mammino

View More author details
Right arrow

Asynchronous Control Flow Patterns with Promises and Async/Await

Callbacks are the low-level building blocks of asynchronous programming in Node.js, but they are far from being developer-friendly. In fact, in the last chapter, we learned techniques to implement different control flow constructs using callbacks, and we can say that they are quite complex and verbose compared to the (low) level of complexity of the tasks they try to accomplish. In particular, serial execution flow, which is the predominant control flow structure in most of the code we write, can easily lead an untrained developer to write code affected by the callback hell problem. On top of that, even if properly implemented, a serial execution flow seems needlessly complicated and error-prone. Let's also remember how fragile error management with callbacks is; if we forget to forward an error, then it just gets lost, and if we forget to catch any exception thrown by some synchronous code, then the program crashes...

Promises

Promises are part of the ECMAScript 2015 standard (or ES6, which is why they are also called ES6 promises) and have been natively available in Node.js since version 4. But the history of promises goes back a few years earlier, when there were dozens of implementations around, initially with different features and behavior. Eventually, the majority of those implementations settled on a standard called Promises/A+.

Promises represent a big step ahead toward providing a robust alternative to continuation-passing style callbacks for propagating an asynchronous result. As we will see, the use of promises will make all the major asynchronous control flow constructs easier to read, less verbose, and more robust compared to their callback-based alternatives.

What is a promise?

A Promise is an object that embodies the eventual result (or error) of an asynchronous operation. In promises jargon, we say that a Promise is pending when the asynchronous operation...

Async/await

As we have just seen, promises are a quantum leap ahead of callbacks. They allow us to write clean and readable asynchronous code and provide a set of safeguards that can only be achieved with boilerplate code when working with callback-based asynchronous code. However, promises are still suboptimal when it comes to writing sequential asynchronous code. The Promise chain is indeed much better than having callback hell, but still, we have to invoke a then() and create a new function for each task in the chain. This is still too much for a control flow that is definitely the most commonly used in everyday programming. JavaScript needed a proper way to deal with the ubiquitous asynchronous sequential execution flow, and the answer arrived with the introduction in the ECMAScript standard of async functions and the await expression (async/await for short).

The async/await dichotomy allows us to write functions that appear to block at each asynchronous operation, waiting...

The problem with infinite recursive promise resolution chains

At this point in the chapter, you should have a strong understanding of how promises work and how to use them to implement the most common control flow constructs. This is therefore the right time to discuss an advanced topic that every professional Node.js developer should know and understand. This advanced topic is about a memory leak caused by infinite Promise resolution chains. The bug seems to affect the actual Promises/A+ specification, so no compliant implementation is immune.

It is quite common in programming to have tasks that don't have a predefined ending or take as an input a potentially infinite array of data. We can include in this category things like the encoding/decoding of live audio/video streams, the processing of live cryptocurrency market data, and the monitoring of IoT sensors. But we can have much more trivial situations than those, for example, when making heavy use of functional programming...

Summary

In this chapter, we've learned how to use promises and async/await syntax to write asynchronous code that is more concise, cleaner, and easier to read.

As we've seen, promises and async/await greatly simplify the serial execution flow, which is the most commonly used control flow. In fact, with async/await, writing a sequence of asynchronous operations is almost as easy as writing synchronous code. Running some asynchronous operations in parallel is also very easy thanks to the Promise.all() utility.

But the advantages of using promises and async/await don't stop here. We've learned that they provide a transparent shield against tricky situations such as code with mixed synchronous/asynchronous behavior (a.k.a. Zalgo, which we discussed in Chapter 3, Callbacks and Events). On top of that, error management with promises and async/await is much more intuitive and leaves less room for mistakes (such as forgetting to forward errors, which is a serious...

Exercises

  • 5.1 Dissecting Promise.all(): Implement your own version of Promise.all() leveraging promises, async/await, or a combination of the two. The function must be functionally equivalent to its original counterpart.
  • 5.2 TaskQueue with promises: Migrate the TaskQueue class internals from promises to async/await where possible. Hint: you won't be able to use async/await everywhere.
  • 5.3 Producer-consumer with promises: Update the TaskQueuePC class internal methods so that they use just promises, removing any use of the async/await syntax. Hint: the infinite loop must become an asynchronous recursion. Beware of the recursive Promise resolution memory leak!
  • 5.4 An asynchronous map(): Implement a parallel asynchronous version of Array.map() that supports promises and a concurrency limit. The function should not directly leverage the TaskQueue or TaskQueuePC classes we presented in this chapter, but it can use the underlying patterns. The function...
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Node.js Design Patterns - Third Edition
Published in: Jul 2020Publisher: PacktISBN-13: 9781839214110
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (2)

author image
Mario Casciaro

Mario Casciaro is a software engineer and entrepreneur, passionate about technology, science and open source knowledge. Mario graduated with a master's degree in software engineering and started his professional career at IBM where he worked for several years on different enterprise products such as Tivoli Endpoint Manager, Cognos Insight, and SalesConnect. Next, he moved to D4H Technologies, a growing SaaS company, to lead the development of a new bleeding-edge product for managing emergency operations in real time. Currently, Mario is the co-founder and CEO of Sponsorama.com, a platform to help online projects raise funds through corporate sponsorship. Mario is also the author of the first edition of Node.js Design Patterns.
Read more about Mario Casciaro

author image
Luciano Mammino

Luciano Mammino is a software engineer born in 1987, the same year that the Nintendo released Super Mario Bros in Europe, which by chance is his favorite video-game. He started coding at the age of 12 using his father's old Intel 386, provided only with the DOS operating system and the qBasic interpreter. After a master's degree in computer science he developed his programming skills mostly as a web developer working mainly as freelancer for companies and startups all around Italy. After a start-up parenthesis of 3 years as CTO and co-founder of Sbaam.com in Italy and in Ireland, he decided to relocate in Dublin to work as senior PHP engineer at Smartbox. He loves developing open source libraries and working with frameworks such as Symfony and Express. He is convinced that the JavaScript fame is still at the very beginning and that this technology will have a huge impact in the future of most of the web-and mobile-related technologies. For this reason, he spends most of his free time improving his knowledge of JavaScript and playing with Node.js.
Read more about Luciano Mammino