I am often replying to Javascript programming questionsabout issues related to a lack of understanding of the asynchronous nature of most Javascript API and the proper way to write asynchronous code. Some documentation or examples found through search engines are outdated and not reflecting 2019's language features and best practices.
There are numerous good blog posts, like this one, to explain the concepts of asynchronous coding and even more to describe correct usage of the Promise pattern, I don't want to write a "me too" article, but rather just focus one three code sample : the good, the bad and the ugly. Or should I say : the modern, the old and the antique ?
So, using three simple code samples, let's see how you can refactor your code from a callback approach (the ugly), to a Promise approach with .then()
constructs (the bad) to a modern Promise approach using async
/await
keywords (the correct way of writing modern code).
The oldest and traditional approach was to pass callback function to your asynchronous function. Upon termination, the asynchronous function would simply call your callback function. Please do not do that anymore.
$ node async_demo_1.js
Started
Ended
callback !
(code)
Notice callback
is called after Ended
because program execution continues while asyncWorker()
is executed.
To avoid having to manage callbacks hell, many programing languages are now proposing the concept of Promises. Converting old callback-based code to Promises is easy :
- immediately return a
new Promise()
object. - the Promise constructor takes one function argument :
(resolve, reject) => { ... }
- whenever a result is available call
resolve(return_value)
or callreject(reason)
in case of an error
$ node async_demo_2.js
Started
Ended
callback !
(code)
Notice callback
is still called after Ended
. Also notice the asynchronous function immediately returns a Promise
object.
This simplifies a lot writing asynchronous code, but you still end up with .then().catch()
nightmare. So, to remove these .then().catch()
the last transformation step is to migrate your code to await
/ async
keywords, as shown below.
$ node async_demo_3.js
Started
callback !
Ended
(code)
Notice the output is now in the logical order. await
blocks the execution until that function finishes. Also notice that the only change made to the asynchronous function is the addition of the async
keyword at the start of it.
Let's finish by looking at how you can wrap AWS Services calls made with the AWS SDK for Javascript{:target="_blank"} with async
and await
. Here is a DynamoDB update
example.
(code)
The idea is the same : the function immediately returns a Promise
. Then your function calls the AWS SDK, using a callback. The successful callback eventually calls resolve(<any data>)
to pass the result back to the caller. In case of error, the error handling code calls reject()
.
To wrap up, going from callback to async
/ await
is pretty straigthforward once you know how to do it. Now that you read this short post, there is no reason to not do it :-). All browser's recent versions do include support for these constructs, so does NodeJS since version 7.6.0.
Top comments (1)
The code with async/await example doesn't have callback function it seems.