The architecture of Node.js expects an application to run in one process and one thread.

And yet, Node.js can handle concurrency just fine.

This is because most of the platform’s features support outsourcing complex work. The outsourcing of complex work is basically asynchronous programming.

In other words, asynchronous programming allows Node.js to remain responsive throughout the application’s lifecycle.

In this post, we will take a look at asynchronous vs synchronous programming in Node.js with an example.

Synchronous Programming in Node.js

To understand the benefits of asynchronous programming, let us first understand how things would look in a typical synchronous approach.

Check out the below source code where we try to read the contents of a file using the Node.js fs module.

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 we run the above program using the command node index.js, we will 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 will wait for the read operation to finish before moving ahead.

Though the console.log statements for ‘Message 2’ and ‘Message 3’ had nothing to do with reading the file, they cannot run until Node.js is able to read the contents of the file.

The below diagram illustrates the flow of our synchronous program.

asynchronous vs synchronous node.js
Synchronous File Read Node.js

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 users. 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 and processes requests sequentially.

This won’t make your application users happy!

Asynchronous Programming in Node.js

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

From a developer’s perspective, asynchronous means that you don’t have to wait until the result of an operation is available.

Check out the below code for accessing the same file. This time we use the asynchronous approach.

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.

There is not much difference between readFile() and readFileSync(). The readFile() has one extra parameter i.e. the 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 from the callback function is executed.

Running the above program gives the below output:

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

What happens in the Asynchronous Approach?

The asynchronous processing of tasks (such as reading a file) depends on the event-driven nature 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 mean time, 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 Node.js. The Node.js platform 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 asynchronous operation.

asynchronous programming node.js
Asynchronous File Read Node.js

Asynchronous vs Synchronous in Node.js

The callback function exposes the major difference between asynchronous and synchronous programming in Node.js.

Apart from the contents of the file, it also contains an additional parameter – err. If an error occurs during the execution of the operation (such as the file not existing), you receive an object containing the corresponding error message as the first argument of the callback.

Though it is good practice to check for the error, the application would continue to run even if you ignore the error.

The case is different with synchronous version of reading the file. There is only one return value from the readFileSync() function i.e. the content. If the file does not exist, the method returns an exception that you have to handle with a try-catch block or else it will interrupt the execution of the entire application.

Conclusion

With this post, we get a sneak peak into both asynchronous vs synchronous programming in Node.js to develop the same functionality. We made use of the fs module to demonstrate the differences.

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

As further reading, you can refer to the post about the Node.js Reactor Pattern that makes it possible for Node.js to handle concurrency.


If you enjoyed this article or found it helpful, consider sharing it with friends and colleagues

You can also connect with me on other platforms:

ProgressiveCoder Newsletter

Twitter

LinkedIn

Youtube

Categories: BlogNodeJS

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *