Pages

[NodeJS] What is a thunk?

What is a thunk?

A thunk, as Michael Fogus defines in his book "Functional Javascript", is "a function that wraps some behavior for later execuation". Specifically, in Node.js, a thunk of a function fn is a function that partially applies all the arguments of fn except the callback. As a result, the returned function accepts only one argument, which is a callback. For example, let's take a look at the readFile function. Its syntax is as following.


var readFile = require('fs').readFile;

readFile('path/to/file', 'utf-8', function(err, data) {
  if (err) throw err;
  console.log(data);
});

You can convert this function readFile into a thunk using a mini module called thunkify. Then, the above code can be rewritten as following.


var thunkify = require('thunkify'),
    readFile = require('fs').readFile,
    tReadFile = thunkify(readFile);

tReadFile('path/to/file', 'utf-8')(function(err, data) {
  if (err) throw err;
  console.log(data);
});

The syntax should be clear from the example above. But why do we need a thunk? Why do we want to extract the callback from a function and then pass it into another function? What's the benefit?

Why do we need a thunk?

The beauty of thunk comes when we combine it with generator to write asynchronous Javascript code without callback hell. Because a thunk is a yieldable object, we can yield thunks inside a generator. We can iterate through the yielded values using generator's next() function. As a result, we get a serie of thunks. We then exeucte these thunks with a callback function, and pass the data back to the generator. It sounds complicated, isn't it? Fortunately, there're existing Node.js modules that handle the generator-based control flow for you such as bluebird and co. Using co and thunk you can write asynchronous code that looks synchronously as following.


var thunkify = require('thunkify'),
    readFile = require('fs').readFile,
    tReadFile = thunkify(readFile),
    co = require('co');

co(function*() {
  var data = yield tReadFile('/path/to/file', 'utf-8');
  console.log('data:', data);
});

How does it work?

To understand how thunk is created, let's look at the source code of thunkify.

  1. From line 2 to 25, a function is created and returned. This function will be the thunk.
  2. The thunk will be called with some arguments. We copy these arguments into an array, named args. In the example above, arguments = ['/path/to/file', 'utf-8']
  3. Since the thunk context of the thunk can be changed depends on how it's called, we save its context in a variable named ctx in line 4.
  4. With the context and arguments set up, we now actually create and return a thunk, line 10 through 24. It's a function that accept a callback, named done.
Now, when you call the thunk tReadFile(function() {/* ... */}), the following will happen.
  1. Line 13-17, we create an anonymous function and push it into args. We'll discuss this anonymous function and and variable called below. At this point, args = ['/path/to/file', 'utf-8', [function]].
  2. Then we try to execute the original function fn with the context of the thunk and the arguments args. If there is error, we will handle it in the callback, done That is, readFile is called with the path-to-file, enconding and the anonymous function, line 13-17, as arguments.
  3. Now, if you remember how the native readFile works, it read the give file and pass error, data to the anonymous function. That means the anonymous function will be executed with arguments = [null, 'content-of-file'] if readFile succeeds, or arguments = [Error] otherwise.
  4. So, the only thing that the anonymous function needs to do is to execute the callback function that we provide, done, with the arguments above.

6 comments:

  1. Hai Author Good Information that i found here,do not stop sharing and Please keep updating us..... Thanks.
    Nodejs Development company
    Hire Nodejs Developers

    ReplyDelete
  2. Thank you for this golden advice you shared here. Thank you for such a great article...
    web development company sydney

    ReplyDelete
  3. Expresstech Softwares is a leading node.js Development Company provider company. Hire Node.js developer from us who are expert in each development aspect. Contact us: +91-9806724185 or Contact@expresstechsoftwares.com

    ReplyDelete
  4. I really appreciate your blog about nodejs and my best wishes for your all upcoming blogs. If you want to Hire Nodejs Developers then you must aware about the technologies.

    ReplyDelete
  5. There is a high demand for this advanced JS framework among web developers. It lets them develop robust websites and applications for different verticals. And these are the reasons which push business to hire node js web development companies out of leading node js development companies available in the global market for your website requirements.

    ReplyDelete