Aus*_*Yun 6 asynchronous callback node.js
function indexArticles(callback) {
fs.readdir("posts/", function(err, files) {
async.map(files, readPost, function(err, markdown) {
async.map(markdown, parse, function(err, results) {
async.sortBy(results, function(obj, callback) {
callback(err, obj.date);
}, function(err, sorted) {
callback( {"articles": sorted.reverse()} );
});
});
});
});
}
Run Code Online (Sandbox Code Playgroud)
我正试图弄清楚如何使这个更漂亮 - 你可以告诉我我正在使用caolan的异步库,但我不确定使用哪种控制流结构.例如,如果我使用async.waterfall,会产生相当多的代码,每个步骤都必须包含在匿名函数中.例如,这只是带有瀑布的嵌套版本的前两行:
function indexArticles(callback) {
async.waterfall([
function(callback) {
fs.readdir("posts/", function(err, files) {
callback(err, files)
})
},
function(files, callback) {
async.map(files, readPost, function(err, markdown) {
callback(err, markdown)
})
}])
}
Run Code Online (Sandbox Code Playgroud)
你会如何改善这一点?
如果有一种方法不仅从左边部分地应用参数,那么我可以看到,例如,
function indexArticles(callback) {
async.waterfall([
async.apply(fs.readdir, "posts/"),
async.apply(async.map, __, readPost),
async.apply(async.map, __, parse),
// etc...
])
}
Run Code Online (Sandbox Code Playgroud)
这是一个有趣的问题,因为您需要将参数绑定到迭代器函数的左侧和右侧,因此,两者bind(也不bindRight是StackOverflow上的一些实现)都不适合您.这里有几个选项:
(1)首先,在你的async.waterfall例子中,你有:
function(callback) {
fs.readdir("posts/", function(err, files) {
callback(err, files)
})
}
Run Code Online (Sandbox Code Playgroud)
这与:
function(callback) {
fs.readdir("posts/", callback)
}
Run Code Online (Sandbox Code Playgroud)
使用Function.bind和这个方法,您indexArticles可以编写整个函数:
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()} );
});
};
Run Code Online (Sandbox Code Playgroud)
哪个稍短.
(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);
};
}
Run Code Online (Sandbox Code Playgroud)
此函数接受函数和任意数量的参数,并undefined在调用函数时将参数列表中的值替换为实际参数.然后你会像这样使用它:
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()} );
});
}
Run Code Online (Sandbox Code Playgroud)
因此,partial(async.map, undefined, readPost, undefined)返回一个函数,当被Async库调用时fn(files, callback),它会填充files第一个undefined,而callback第二个函数则以undefined调用结束async.map(files, readPost, callback).
(3)还有一个版本的partial对Function.prototype在该StackOverflow的答案,让您使用的语法:async.map.partial(undefined, readPost, undefined); 但是,我可能会建议不要这样修改Function.prototype,只是partial作为一个函数使用.
最后,由您决定哪种方法最易读和可维护.