I recently came across some node.js code that has an anonymous function enclosed in parentheses immediately after a function call. Could somebody please explain to me what is going on with the syntax here?
var fs = require('./continuable-style-fs');
fs.readFile('mydata.txt')(function (text) {
// Do something
console.log(text);
}, function (error) {
// Handle error
throw error
});
continuable-style-fs
is returning versions of the built-in fs
methods that return functions instead of accepting a callback as an argument.
With that in mind, the callback is being passed to the function returned by fs.readFile()
. The callback is then called when the read is complete, just like the original fs.readFile()
would.
When looking at the code for continuable-style-fs, the second function passed is the function that receives errors. This is more promise-like than the "error-first" callback approach of async node core methods.
It means that fs.readFile('mydata.txt')
returns a function, which is immediately invoked.
It might make more sense to look at it like so...
var fs = require('./continuable-style-fs');
var fn = fs.readFile('mydata.txt');
fn(function (text) {
// Do something
console.log(text);
}, function (error) {
// Handle error
throw error
});
Without you posting the function require() it's a little hard to tell since we don't know exactly what that returns. If you provide more info I'm sure I can figure it out, otherwise I'm slightly guessing at the answer right now. OK so here it goes:
in JavaScript you can have an anonymous function that takes a parameter. You would initiate that function as follows:
(function (variable){
...
...
})(myVariable);
So if required() returns an object, then fs.readFile () would be a method attached to that object (through prototyping). In this case it looks like it's a method that itself returns an anonymous function that will then receive either the variable from the //Do something
section or it will receive the error/variable from the //Handle error
So in the end the you'll have
fs.readFile('mydata.txt')(someVariable);
Which if readFile does return an anonymous function then it will look like:
(function foo (variable){})(someVariable);
This as another answers mentions is simply a slightly different approach to using callbacks. I hope that helps, and is clear.
What's happening is this, the following code:
fs.readFile('mydata.txt')(function (text) {
// Do something
console.log(text);
}, function (error) {
// Handle error
throw error
});
Can be translated to this:
var file_reader = fs.readFile('mydata.txt');
file_reader(function (text) {
// Do something
console.log(text);
}, function (error) {
// Handle error
throw error
});
Which can then be translated to this:
function read_file_handler (text) {
// Do something
console.log(text);
}
function file_error_handler (error) {
// Handle error
throw error
}
var file_reader = fs.readFile('mydata.txt');
file_reader(read_file_handler, file_error_handler);
Basically, javascript allows you to:
Treat functions as data
Immediately use the result of any expression or function call
Number 2 is interesting. Because it allows you to do things like this:
function foo () {
return "a,b,c";
}
var abc_array = foo().split(',');
Note that in the example above split
is a String
method but we can call it immediately after foo()
because it returns a string.
Similarly we can do this:
function foo () {
return function () {console.log('hello')}
}
foo()();
Here calling foo()
returns a function. We can assign it to a variable and call that but we can also call it immediately as we do above.