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.