My name is Gaurang and I've been working with Node.js for the past 5 years.
This article is part of the "My guide to getting through the maze of callbacks and promises" series. It's a 3-part series where I talk about writing asynchronous code with Node.js.
The articles are intermediate-level and it is expected that the reader already has basic familiarity with Node.js syntax and the constructs related to asynchronous programming in it. Such as callbacks, promises, and async-await.
Table of Contents
Sync of Async what?
Before I go ahead and beef about synchronous functions, I guess it would be customary for me to briefly describe synchronous as well as asynchronous functions.
Many Node.js packages provide synchronous alternatives of their asynchronous functions.
For example, the
fs package has
fs.readFile (which works asynchronously) and
fs.readFileSync (which works synchronously).
The working of
fs.readFileSync is similar to traditional functions.
Your program calls the method and waits for the file to be read. Once the file is completely read, it returns the contents. The program then resumes execution of the rest of the code.
Now reading a file is a slow I/O operation that could take anywhere between a few hundred nanoseconds to a few seconds.
So when our program calls the asynchronous
fs.readFile method, it does not wait for the method to read the entire file and return the contents. Our program moves ahead with the execution of the rest of the code immediately; while
fs.readFile continues with the reading task in parallel.
If there's any code you want to execute after the file contents have been read, you need to wrap the code in a function and pass that function to
fs.readFile will call that function as soon as the file contents have been read.
What's wrong with using sync versions of async functions?
Callback-hell has become a thing of the past.
However, I often come across codebases where callbacks, promises, and async-await have been mixed together. Turning the code into a hotchpotch.
I sympathize with the people that have to work with such codebases.
Understanding callbacks and promises is difficult. Writing code with callbacks is difficult. Understanding the difference between synchronous and asynchronous functions is difficult.
Sometimes I see people retreating to synchronous versions of library methods because they're more convenient. E.g.
Node.js is single-threaded. And therefore, just one long-running synchronous (blocking) task is enough to degrade the performance of the entire application.
Asynchronous functions are designed to be non-blocking and to avoid delays. Using synchronous versions of asynchronous functions may seem like an easy solution at first, but it is the devil in disguise. It can cause delays all over the application; leading to frustration for developers and users alike.
Of course, if you're writing a small independent one-time script, it may not matter much. But in large production-level applications, this is going to cause unnecessary bottlenecks.
Here's a short demo of how a synchronous method call affects the rest of the application.
This script starts a barebones Node.js server that has three APIs.
quick-api API is supposed to return a response immediately.
But, if you call
slow-sync-api, it does not return until
slow-sync-api returns. This is because Node.js is single-threaded. And
slow-sync-api calls a synchronous method that does not let the main thread do anything else till its execution is complete. It blocks all other requests.
However, if you call
quick-api works as expected. This is because
slow-async-api does not block the main thread till its execution is complete. The work of the asynchronous function is deferred to a worker thread and the main thread waits for the execution to complete. Meanwhile, the main thread is free to fulfil other requests.
In conclusion, using the synchronous versions of asynchronous functions is a bad practice. It can lead to unexpected behavior and performance issues. If you need to use an asynchronous function, it's best to use the asynchronous version. This will help you avoid any potential problems and ensure that your code is as efficient as possible.
I've put a lot of work into this article. And I hope that it has been helpful. If you have any questions, please feel free to leave a comment below. I'd really appreciate it if you could like and share the article! 😊
Top comments (0)