在Nodejs中堆叠asynchronouscallback事件的最佳方法

我正在使用Node和NodeWebkit编写本地音乐stream应用程序。 在我的应用程序中,我扫描任何目录的音乐文件夹,加载专辑封面,然后在HTML中显示艺术。 但是,在每个asynchronouscallback结束时检测.forEach()迭代器结束的逻辑不会从开发人员的angular度来创build干净的代码。 从逻辑上讲,它的工作原理,但如果我要解开这串依赖关系,我不得不重写所有的依赖关系。

这是我的代码片段:

 // Fetch the music albums fs.readdir("./music", function(err, files) { if (err) { //return console.error(err); } //document.write(JSON.stringify(files)); // Look specifically for music album folders (directories) filterDirectories("./music", files, function(dirs){ dirs.forEach(function(dir, index, array){ fs.readFile('./music/' + dir + "/album.json", 'utf-8', function (err, data) { data = JSON.parse(data); if (err) { return console.error(err); } // Create a li item for every album, and append it to the unordered list var li = $('<li><img /><a target="_blank"></a></li>'); li.find('a') .attr('href', '#') .text(data.album_name); li.find('img').attr('src', './music/' + dir + '/' + data.album_art_loc).css('width:512px;height:512px;'); lis.push(li); // Is this the last album folder? if(index == array.length-1) { // Go through the array lis.forEach(function(item, index, array){ // add to the ul element item.appendTo(ul); // Have we added the last one to the ul element? if(index == array.length - 1){ // Ok, now we initialize the flipster plugin to make it look 3D and advanced $('.flipster').flipster({ style: 'carousel' }); } }); } }); }); }); }); 

注意1,Array.forEach是同步的。 所以要初始化flipster,你不需要检查最后一个循环的结束。 你可以把它放在循环之后。

注意2,要读取每个album.json文件,你有正确的方法。 虽然,您可能想要使用助手,如asynchronous 。 通常存在处理这种情况的方式。

请检查代码,我使用async重写了它。 我不保证它没有bug,但最终的代码应该非常相似。

注意3,最初的fs.readdir和filterDirectories的调用似乎可以合并成一个asynchronous函数。

注意4,这可能值得阅读

代码重写

 var async = require('async') var musicFiles; var musicDirs; var lis = []; async.series([ function (next) { fs.readdir("./music", function(err, files) { if (err) next(err); musicFiles = files; next(); }); }, function (next) { filterDirectories("./music", files, function(dirs){ musicDirs = dirs; next(); }); }, function (next) { var todos = []; musicDirs.forEach(function(dir){ todos.push(function (nextTodo) { fs.readFile('./music/' + dir + "/album.json", 'utf-8', function (err, data) { if (err) nextTodo(err); lis.push(createLi(JSON.parse(data))); nextTodo(); }); }) }); async.parallelLimit(todos, 4, next); }, function (next) { lis.forEach(function(li){ li.appendTo(ul); }); $('.flipster').flipster({ style: 'carousel' }); } ], function () { console.log("All done !") }) function createLi (data) { var li = $('<li><img /><a target="_blank"></a></li>'); li.find('a') .attr('href', '#') .text(data.album_name); li.find('img').attr('src', './music/' + dir + '/' + data.album_art_loc).css('width:512px;height:512px;'); return li } 

心连心。