This is an interesting problem, since you need to bind the arguments both to the left and to the right of your iterator functions, so neither bind
/ nor bindRight
(of which several implementations on StackOverflow) will work for you. There are several options here:
(1) First, in your async.waterfall
example, you have:
function(callback) { fs.readdir("posts/", function(err, files) { callback(err, files) }) }
which matches with:
function(callback) { fs.readdir("posts/", callback) }
Using Function.bind
and this method, you can write your entire indexArticles
function:
function indexArticles(callback) { async.waterfall([ fs.readdir.bind(this, 'posts/'), function(files, cb) { async.map(files, readPost, cb); }, function(text, cb) { async.map(text, parse, cb); }, function(results, cb) { async.sortBy(results, function(obj, callback) { callback(null, obj.date); }, cb) } ], function(err, sorted) { callback( {"articles": sorted.reverse()} ); }); };
It is a little shorter.
(2) If you really want to avoid wrapper functions, you can use the partial function application. First, at the top of your file (or in a module, etc.) Define a function called partial
:
var partial = function(fn) { var args = Array.prototype.slice.call(arguments, 1); return function() { var currentArg = 0; for(var i = 0; i < args.length && currentArg < arguments.length; i++) { if (args[i] === undefined) args[i] = arguments[currentArg++]; } return fn.apply(this, args); }; }
This function takes a function and any number of arguments and replaces the undefined
values ββin the argument list with the actual arguments when the function is called. Then you will use it as follows:
function indexArticles(callback) { async.waterfall([ fs.readdir.bind(this, 'posts/'), partial(async.map, undefined, readPost, undefined), partial(async.map, undefined, parse, undefined), partial(async.sortBy, undefined, function(obj, callback) { callback(null, obj.date); }, undefined) ], function(err, sorted) { callback( {"articles": sorted.reverse()} ); }); }
So, partial(async.map, undefined, readPost, undefined)
returns a function that when calling the Async library as fn(files, callback)
fills the files
for the first undefined
and callback
for the second undefined
, ending the call async.map(files, readPost, callback)
.
(3) There is also a partial
version for Function.prototype
at fooobar.com/questions/920640 / ... that allows you to use the syntax: async.map.partial(undefined, readPost, undefined)
; however, I would probably recommend not changing Function.prototype
this way and just use partial
as a function.
In the end, it is up to you which method is the most readable and supported.