Asynchronous vs Synchronous Programming in Node.js

Asynchronous vs Synchronous Programming in Node.js

Make the right choice

The single-threaded nature of Node.js expects an application to run in one process and one thread.

And yet, Node.js can handle concurrency just fine because most of the platform’s features support outsourcing complex work.

This outsourcing of complex work is asynchronous programming.

Asynchronous programming allows your Node.js apps to remain responsive throughout the application’s lifecycle.

Synchronous Programming in Node.js

You might appreciate the benefits of async programming after seeing how things work in the typical synchronous approach.

Here's an example:

import { readFileSync } from 'fs';

console.log('Message 1');
const content = readFileSync('test-file.txt', 'utf-8');
console.log('File Content: ', content);
console.log('Message 2');
console.log('Message 3');

If you run the above program using the command you get the below output:

$ node index.js
Message 1
File Content: Hello from File
Message 2
Message 3

The readFileSync() function is synchronous. This means the program waits for the operation to finish reading the file before moving ahead.

You can see that Message 2 and Message 3 had nothing to do with the file. But Node.js won't print them until it has finished reading the contents of the file.

That's synchronous programming. The below illustration explains it better:

asynchronous vs synchronous node.js

As you can see, everything happens in sequence.

You won’t notice the drawbacks of synchronous programming when reading a single small text file. However, if you need to execute a large number of such operations or the file size is significantly bigger, things may take a long time.

You can still get away with executing these operations in the main thread if they are processed away from the typical user flow. However, if synchronous operations get into the flow of user activity, parallel requests can get delayed. This is because Node.js works with a single-thread that processes requests sequentially.

This won’t make your application users happy!

JavaScript's Async/Await versus Promises: The Great Debate | by Paige  Niedringhaus | ITNEXT

Asynchronous Programming in Node.js

Considering the problems with the synchronous approach, it is a good thing that most Node.js features support asynchronous behaviour.

From a developer’s perspective, asynchronous means that your program doesn't have to wait until the result of an operation is available. It can handle other stuff.

Check the below example:

import { readFile } from 'fs';

console.log('Message 1');

readFile('test-file.txt', 'utf-8', (err, content) => {
    console.log('File Content: ', content);
});

console.log('Message 2');
console.log('Message 3');

readFile() is the async version of reading a file. Every operation in the fs module of Node.js has a synchronous and asynchronous method.

Only difference between readFile() and readFileSync() is the one extra parameter readFile() takes as input. This extra parameter is a callback function.

In contrast to the synchronous execution, the file is read asynchronously. This means that the two console.log() statements after the call to readFile() are executed immediately. They don’t wait for the file to be read.

Once the contents of the file are available, the console.log() statement within the callback function is also executed.

Here's the output:

$ node index.js
Message 1
Message 2
Message 3
File Content: Hello from File

What's going on over here?

When you chose to go with the async approach, you are basically using the event-driven capabilities of Node.js

Internally, the request to read the file is passed to the operating system. The callback function is registered to handle the response. The operating system takes over the processing of the read request. In the meantime, the main thread of Node.js is free to execute other tasks such as the console.log() statements.

Finally, when the read operation is completed, the result is returned to the execution flow. Node.js takes care of calling the registered callback function with the result from the operation. You can read more about all the behind-the-scenes magic in this post on Node.js Reactor Pattern.

The below illustration shows the difference in program flow in the case of an asynchronous operation.


A large part of the Node.js standard API supports both the async and sync approaches.

However, the natural way to develop applications using Node.js is using the asynchronous approach. The sooner we embrace this fact, the better we can leverage the true potential of Node.js.

If you enjoyed this post and found it useful, consider sharing it with friends and colleagues.

You can also connect with me on other platforms:

Twitter

LinkedIn

Youtube

Did you find this article valuable?

Support Saurabh Dashora by becoming a sponsor. Any amount is appreciated!