Nodejs中堆叠异步回调事件的最佳方式
Optimal way for stacking asynchronous callback events in Nodejs
我正在使用 Node 和 NodeWebkit 编写本地音乐流应用程序。在我的应用程序中,我扫描音乐文件夹中的任何目录,加载专辑封面,然后在 html 中显示专辑封面。但是,从开发人员的角度来看,在每个异步回调结束时检测 .forEach()
迭代器结束的逻辑并不能生成干净的代码。从逻辑上讲它是可行的,但如果我要解开这串依赖项,我将不得不重写所有内容。
这是我的代码片段:
// 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,你不需要检查 last 循环的结束。你可以把它放在循环之后。
注2,阅读每个album.json文件,你有正确的方法。虽然,您可能想要使用 async 这样的助手。这通常是为了处理这种情况而存在的。
请检查代码,我使用异步重写了它。我不保证它没有错误,但最终代码应该非常相似。
注意 3,最初的 fs.readdir 和对 filterDirectories 的调用似乎可以合并到一个异步函数中。
注释 4,可能值得一读 this
代码重写
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
}
hth.
我正在使用 Node 和 NodeWebkit 编写本地音乐流应用程序。在我的应用程序中,我扫描音乐文件夹中的任何目录,加载专辑封面,然后在 html 中显示专辑封面。但是,从开发人员的角度来看,在每个异步回调结束时检测 .forEach()
迭代器结束的逻辑并不能生成干净的代码。从逻辑上讲它是可行的,但如果我要解开这串依赖项,我将不得不重写所有内容。
这是我的代码片段:
// 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,你不需要检查 last 循环的结束。你可以把它放在循环之后。
注2,阅读每个album.json文件,你有正确的方法。虽然,您可能想要使用 async 这样的助手。这通常是为了处理这种情况而存在的。
请检查代码,我使用异步重写了它。我不保证它没有错误,但最终代码应该非常相似。
注意 3,最初的 fs.readdir 和对 filterDirectories 的调用似乎可以合并到一个异步函数中。
注释 4,可能值得一读 this
代码重写
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
}
hth.