Order of execution in Node.js

I have been trying to learn node.js, but one thing I couldn't understand was the order of execution of this code:

var zlib = require("zlib");
var input = '.............text...............';
zlib.deflate(input, function(err, buffer) {
  if (!err) {
    console.log("deflate (%s): ", buffer.length, buffer.toString('base64'));
    zlib.inflate(buffer, function(err, buffer) {
      if (!err) {
        console.log("inflate (%s): ", buffer.length, buffer.toString());
      }
    });
    zlib.unzip(buffer, function(err, buffer) {
      if (!err) {
        console.log("unzip deflate (%s): ", buffer.length, buffer.toString());
      }
    });
  }
});

zlib.deflateRaw(input, function(err, buffer) {
  if (!err) {
    console.log("deflateRaw (%s): ", buffer.length, buffer.toString('base64'));
    zlib.inflateRaw(buffer, function(err, buffer) {
      if (!err) {
        console.log("inflateRaw (%s): ", buffer.length, buffer.toString());
      }
    });
  }
});

Output:

deflate (18):  eJzT00MCJakVJXqoAABxWgbO
deflateRaw (12):  09NDAiWpFSV6qAAA
inflate (32):  .............text...............
unzip deflate (32):  .............text...............
inflateRaw (32):  .............text...............

How come "deflateRaw" is output before "inflate"? I know node.js could runs asynchronously, but could anyone explain why this piece of code is asynchronous, and how the order of execution is determined?

Well, it is asynchronous :)

As soon as you pass a callback function to a piece of the async code you don't know which order will it be executed.

You can think of your code order following way:

Flow1:
start deflate with cb1;
start deflateRaw with cb2;
done, the order of starting was guaranteed but not the oder of callbacks execution

Flow2: either cb1 or cb2 starts to get executed

etc...

I know node.js could runs asynchronously, but could anyone explain why this piece of code is asynchronous?

Why the zliblibrary is asynchronous, I cannot say for sure. It may use intermediate files for I/O, and we know that I/O is (generally, preferably) asynchronous in node.js. It could also use a worker process behind the scenes or some other asynchronous mechanism.

Asynchronous code requires either callbacks, promises, streams, or some other type of control flow pattern.

However, you could use a callback with synchronous code, so you're right to ask how you would know.

I think the best advice is to assume it's asynchronous if it takes a callback. To handle such a case, the code you want to run after asynchronous function A should just go into the callback, whether it is synchronous or asynchronous. That way, you know it will work. The API developer designed it that way for a reason, so don't try to fight their design by exploiting something that may be synchronous. Just go with the flow :)

The reasons this is safe are:

  1. The developer writing the library designed it that way for a reason - trust they know what they are doing and don't worry about the details of why they did it that way.
  2. Putting the next line of code into a callback is safe whether synchronous or asynchronous, but putting it on the next line is only safe for synchronous code. One is guaranteed to work, one is not. Choose the safe approach.