1

In Node.js, I can do almost any async operation one of two ways:

var file = fs.readFileSync('file.html')

or...

var file
fs.readFile('file.html', function (err, data) {
  if (err) throw err
  console.log(data)
})

Is the only benefit of the async one custom error handling? Or is there really a reason to have the file read operation non-blocking?

alt
  • 13,357
  • 19
  • 80
  • 120
  • 1
    While you're in a blocking call, no other code can run. You don't want that. – SLaks Feb 06 '14 at 18:37
  • http://stackoverflow.com/questions/13858909/synchronous-vs-asynchronous-code-with-node-js – xhallix Feb 06 '14 at 18:37
  • 1
    It's for your convenience, so you can choose what to do, and generally you should opt for the async methods to not block the thread. – adeneo Feb 06 '14 at 18:40

4 Answers4

5

These exist mostly because node itself needs them to load your program's modules from disk when your program starts. More broadly, it is typical to do a bunch a synchronous setup IO when a service is initially started but prior to accepting network connections. Once the program is ready to go (has it's TLS cert loaded, config file has been read, etc), then a network socket is bound and at that point everything is async from then on.

Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • @alt The best answer, IMO. Why? Because most Node beginners pick up very quickly that async is the dominant style in Node -- some not even realizing that sync style is possible UNTIL they actually see a sync flavor of an API! However, once they do realize that sync API is available, there's no guidance in standard documentation on when to prefer it over async. – Harry Nov 21 '20 at 04:55
4

Asynchronous calls allow for the branching of execution chains and the passing of results through that execution chain. This has many advantages.

For one, the program can execute two or more calls at the same time, and do work on the results as they complete, not necessarily in the order they were first called.

For example if you have a program waiting on two events:

var file1;
var file2;

//Let's say this takes 2 seconds
fs.readFile('bigfile1.jpg', function (err, data) {
  if (err) throw err;
  file1 = data;
  console.log("FILE1 Done");
});    

//let's say this takes 1 second.
fs.readFile('bigfile2.jpg', function (err, data) {
  if (err) throw err;
  file2 = data;
  console.log("FILE2 Done");
});

console.log("DO SOMETHING ELSE");

In the case above, bigfile2.jpg will return first and something will be logged after only 1 second. So your output timeline might be something like:

@0:00: DO SOMETHING ELSE
@1:00: FILE2 Done
@2:00: FILE1 Done

Notice above that the log to "DO SOMETHING ELSE" was logged right away. And File2 executed first after only 1 second... and at 2 seconds File1 is done. Everything was done within a total of 2 seconds though the callBack order was unpredictable.

Whereas doing it synchronously it would look like:

file1 = fs.readFileSync('bigfile1.jpg');
console.log("FILE1 Done");
file2 = fs.readFileSync('bigfile2.jpg');
console.log("FILE2 Done");
console.log("DO SOMETHING ELSE");

And the output might look like:

@2:00: FILE1 Done
@3:00: FILE2 Done
@3:00  DO SOMETHING ELSE

Notice it takes a total of 3 seconds to execute, but the order is how you called it.

Doing it synchronously typically takes longer for everything to finish (especially for external processes like filesystem reads, writes or database requests) because you are waiting for one thing to complete before moving onto the next. Sometimes you want this, but usually you don't. It can be easier to program synchronously sometimes though, since you can do things reliably in a particular order (usually).

Executing filesystem methods asynchronously however, your application can continue executing other non-filesystem related tasks without waiting for the filesystem processes to complete. So in general you can continue executing other work while the system waits for asynchronous operations to complete. This is why you find database queries, filesystem and communication requests to generally be handled using asynchronous methods (usually). They basically allow other work to be done while waiting for other (I/O and off-system) operations to complete.

When you get into more advanced asynchronous method chaining you can do some really powerful things like creating scopes (using closures and the like) with a little amount of code and also create responders to certain event loops.

Sorry for the long answer. There are many reasons why you have the option to do things synchronously or not, but hopefully this will help you decide whether either method is best for you.

Arjun Mehta
  • 2,500
  • 1
  • 24
  • 40
0

The benefit of the asynchronous version is that you can do other stuff while you wait for the IO to complete.

fs.readFile('file.html', function (err, data) {
  if (err) throw err;
  console.log(data);
});

// Do a bunch more stuff here. 

// All this code will execute before the callback to readFile, 
// but the IO will be happening concurrently. :)
Paul
  • 139,544
  • 27
  • 275
  • 264
  • Characterizing this as one being "better" than the other is misleading people about an already confusing topic. If your program handles network requests, you must use async exclusively. Both serve purposes in node but there are very specific cases where one is correct and the other is incorrect but there's almost never a case where you "choose" one to get a benefit. – Peter Lyons Feb 06 '14 at 19:00
  • @Peter Lyons, I'm not sure that sure if English is your first language, but it seems like you have good command of the language. Generally things can have both pros and cons. Something can have a "benefit" without being "better" than the alternatives. I think this answer makes it obvious that you don't want to block if you have any event handlers listening to network requests. It certainly doesn't characterize async as better than synchronous or vice-versa. – Paul Apr 15 '18 at 00:56
0

You want to use the async version when you are writing event-driven code where responding to requests quickly is paramount. The canonical example for Node is writing a web server. Let's say you have a user making a request which is such that the server has to perform a bunch of IO. If this IO is performed synchronously, the server will block. It will not answer any other requests until it has finished serving this request. From the perspective of the users, performance will seem terrible. So in a case like this, you want to use the asynchronous versions of the calls so that Node can continue processing requests.

The sync version of the IO calls is there because Node is not used only for writing event-driven code. For instance, if you are writing a utility which reads a file, modifies it, and writes it back to disk as part of a batch operation, like a command line tool, using the synchronous version of the IO operations can make your code easier to follow.

Louis
  • 146,715
  • 28
  • 274
  • 320