Writing Asynchronous Programs in JavaScript
There is no doubt that JavaScript, despite its history, has become to be one of the most popular programming languages today. JavaScript, due to its asynchronous nature, can present some challenges for those who are new to the language. In this article, we are going to write small async programs using promises and async/await. Using these examples, we are going to identify some simple patterns that you can use for your own programs.
If you are new to JavaScript, you may want to first check out my other
article before reading this one.
All the code examples in this article are written for the Node environment. If you don’t have Node installed, you can see the Appendix 1 for instructions. Even though all the programs are written for Node, you can apply the same principles for scripts running in the browser. Also, all the code examples for this article are available on Gitlab.
Introduction
Whether or not people believe that JavaScript is a real programming language,
the reality is that it's not going to go anywhere anytime soon. If you are a web
developer you might as well spend some time and learn its good and bad parts.
JavaScript is single-threaded and favors non-blocking asynchronous flows. If you
are new to the language, it can become really frustrating when things don't work
the way you expect them to. Asynchronous programming demands more patience and a
different kind of thinking that's different from synchronous programming.
In the synchronous model everything happens in a sequence one at a time. Because
of that it's easier to reason about programs. But in the asynchronous model,
operations can start or finish in any order at any point in time. Because of
that simply relying on a sequence is not sufficient. Asynchronous programming
demands more thought in terms of program flow and design.
In this article, we are going to explore a couple of short async programs. We
are going to start with simple programs and work our way up to more complex
ones. Below is an overview of the scripts that we are going to be writing:
-
A script that writes the content of a file to a new file.
-
A script that writes the contents of multiple files to new files.
-
A script that parses and formats CSV files in a directory and outputs new CSV
files to another folder.
Promises and Async/await
Let's take a moment and quickly review the basics of promises and async/await.
Promises
-
A promise is an object that represents the result of an asynchronous
operation. -
A promise is either resolved with a "success" value or rejected with a
"failure" value. -
Generally speaking, resolved values are accessed with a callback's argument to
athen
block. And the rejected values are access with a callback's argument
to acatch
block. -
In modern JavaScript environments, you can access a promise constructor
through the global object asPromise
. -
A promise can be created using the
Promise
constructor using thenew
keyword. That is:const p = new Promise((r, j) => {});
The
r
callback is used to resolve the promise with a value and thej
callback is used to reject the promise. -
The
Promise
constructor has some useful static methods likeall
,race
,
resolve
, andreject
. Theall
method accepts an array of promises and
will attempt to resolve all of them concurrently and return a promise that
resolves to an array with the resolved values. Therace
methods takes an
array of promises and resolves or rejects the first promise that finishes. The
resolve
method creates a promise and resolves it to the given value. The
reject
method creates a promise and rejects it with the given value.
Async/await
-
The purpose of async/await functions is to simplify the behavior of using
promises synchronously and to perform some behavior on a group of Promises.
From MDN -
Just as Promises are similar to structured callbacks, async/await is similar
to combining generators and promises. From MDN -
A function can be marked as an asynchronous function with the
async
keyword.
That is:async function hello() {}
orconst hello = async() => {};
. -
An
async
function always returns a promise. If a value is returned from an
async
function, it will be implicitly wrapped in a promise. -
If there is an uncaught exception thrown inside an
async
function, the
promise returned is rejected with the exception. -
The
await
operator can be used inside anasync
function before statements
that return a promise. In that case, the execution of the function is "paused"
until the promise is resolved or rejected. -
The
await
operator is only valid inside anasync
function.
You can read the rest of the article on medium.com
I believe it is essential to understand callbacks before promises and async/await. We need to know what problems callbacks cause and why we used them in the first place. After that it makes sense to use promises, convert callbacks to promises and finally use them with async/await to write easily readable code.