function indexArticles(callback) { fs.readdir("posts/",function(err,files) { async.map(files,readPost,markdown) { async.map(markdown,parse,results) { async.sortBy(results,function(obj,callback) { callback(err,obj.date); },sorted) { callback( {"articles": sorted.reverse()} ); }); }); }); }); }
我正试图弄清楚如何使这个更漂亮 – 你可以告诉我我正在使用caolan的异步库,但我不确定使用哪种控制流结构.例如,如果我使用async.waterfall,会产生相当多的代码,每个步骤都必须包含在匿名函数中.例如,这只是带有瀑布的嵌套版本的前两行:
function indexArticles(callback) { async.waterfall([ function(callback) { fs.readdir("posts/",files) { callback(err,files) }) },function(files,callback) { async.map(files,markdown) { callback(err,markdown) }) }]) }
你会如何改善这一点?
如果有一种方法不仅从左边部分地应用参数,那么我可以看到,例如,
function indexArticles(callback) { async.waterfall([ async.apply(fs.readdir,"posts/"),async.apply(async.map,__,readPost),parse),// etc... ]) }
解决方法
这是一个有趣的问题,因为您需要将参数绑定到迭代器函数的左侧和右侧,因此bind / norRightRight(其中StackOverflow上有一些实现)都不适合您.这里有几个选项:
(1)首先,在async.waterfall示例中,您有:
function(callback) { fs.readdir("posts/",files) { callback(err,files) }) }
这与:
function(callback) { fs.readdir("posts/",callback) }
使用Function.bind和this方法,可以编写整个函数indexArticles:
function indexArticles(callback) { async.waterfall([ fs.readdir.bind(this,'posts/'),cb) { async.map(files,cb); },function(text,cb) { async.map(text,function(results,cb) { async.sortBy(results,callback) { callback(null,obj.date); },cb) } ],sorted) { callback( {"articles": sorted.reverse()} ); }); };
哪个稍短.
(2)如果你真的想避免包装函数,你可以使用一种部分函数应用程序.首先,在文件的顶部(或在模块中等),定义一个名为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); }; }
此函数接受函数和任意数量的参数,并在调用函数时用参数列表中的实际参数替换参数列表中的未定义值.然后你会像这样使用它:
function indexArticles(callback) { async.waterfall([ fs.readdir.bind(this,partial(async.map,undefined,undefined),partial(async.sortBy,undefined) ],sorted) { callback( {"articles": sorted.reverse()} ); }); }
因此,undefined)返回一个函数,当异步库作为fn(文件,回调)调用时,它会填充第一个未定义的文件,以及第二个未定义的回调,结束在调用async.map(files,callback)时.
(3)在this StackOverflow answer处还有一个部分用于Function.prototype的版本,允许您使用以下语法:async.map.partial(undefined,undefined);但是,我可能会建议不要以这种方式修改Function.prototype,只使用partial作为函数.
最后,由您决定哪种方法最易读和可维护.