我正在开发一个使用文件树的Web应用程序。前端JavaScript向我的Node.js服务器执行ajax请求,该服务器调用我的browse2导出函数。然后,该函数负责为我的函数getFolderContents()提供正确的路径,该函数以递归方式构建文件系统层次结构对象结构。
我的问题是我目前正在同步做事。在研究了Node.js的内部工作原理后,我似乎不惜一切代价避免同步操作。因此,我想将我的代码转换为异步工作。但是,我无法使其正常运行,而且我的所有解决方案都令人费解。
我尝试使用" async"来管理流程。包。想弄清楚,我没有运气。我尝试实现自己的计数器/循环/回调系统来确定进程何时完成执行。最终,我想我无法绕过异步执行流程。
我想问两个问题: 1.在这种情况下,同步而不是异步执行此请求是否有害? 2.如果对第一个问题是肯定的,我应该如何将此代码转换为异步?
注意:当我尝试异步执行操作时,我使用了每个同步函数的异步对应函数。
以下是我的同步(工作)代码:
var path = require('path');
var fs = require('fs');
exports.browse2 = function(request, response) {
var tree = getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\');
response.send(tree);
};
function getFolderContents(route) {
var branch = {};
branch.title = path.basename(route);
branch.folder = true;
branch.children = [];
var files = fs.readdirSync(route);
var size = files.length;
for (var i = 0; i < size; i++) {
var file = files[i];
var concatPath = path.join(route, file);
if (fs.lstatSync(concatPath).isDirectory())
branch.children.push(getFolderContents(concatPath));
else
branch.children.push({
"title" : path.basename(file),
"path" : file
});
}
return branch;
}
我感谢所有的投入!
编辑:
添加了异步代码尝试。没完全工作。只收到树的一部分。
exports.browse2 = function(request, response) {
getFolderContents(
'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\',
function(tree) {
response.send(tree);
});
};
function getFolderContents(route, callback) {
var branch = {};
branch.title = path.basename(route);
branch.folder = true;
branch.children = [];
fs.readdir(route, function(err, files) {
files.forEach(function(file) {
var concatPath = path.join(route, file);
fs.lstat(concatPath, function(err, stats) {
if (stats.isDirectory())
branch.children.push(getFolderContents(concatPath, callback));
else
branch.children.push({
"title" : path.basename(file),
"path" : file
});
callback(branch);
});
});
});
}
答案 0 :(得分:1)
您遇到的基本问题是,当您使用异步调用时,您不能仅仅将函数分配给函数返回。异步的全部意义在于函数不会等待。例如:
function get_data(a) {
var data = some_async_call(a);
//at this point, data is undefined because execution won't wait on the calls to finish
data.do_something(); // this breaks because of the above
}
因此,您所做的是将匿名函数传递给称为回调的异步函数,异步函数在操作实际完成后调用该函数。上面的例子将成为这个:
function get_data(a) {
some_async_call(a, function(data) {
data.do_something();
});
}
function some_async_call(variable, callback) {
call_async({
data: variable,
success: callback
});
}
在你的情况下看起来像这样:
exports.browse2 = function(request, response) {
getFolderContents('C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\', function(tree) {
response.send(tree);
});
};
function getFolderContents(route, callback) {
var branch = {};
branch.title = path.basename(route);
...
callback(branch);
}
如果您熟悉setTimetout,这就是它的工作原理 - 设计模式是传递一个完成工作的匿名函数,然后在数据/信息实际可用后执行该函数。
答案 1 :(得分:0)
我设法让它发挥作用。以下是我对自己问题的回答:
最好异步执行任务,因为这样做会导致应用程序阻止其他用户接收响应,直到后续请求被响应为止。
将同步代码转换为异步代码的方法是使用并行循环。我的具体案例的代码是:
var path = require('path');
var fs = require('fs');
exports.browse2 = function(request, response) {
getFolderContents(
'C:\\Users\\AccountName\\folder1\\folder2\\folder3\\test\\',
function(err, tree) {
if (err)
throw err;
response.send(tree);
});
};
function getFolderContents(route, callback) {
var branch = {};
branch.title = path.basename(route);
branch.folder = true;
branch.children = [];
fs.readdir(route, function(err, files) {
if (err)
return callback(err);
var pending = files.length;
if (!pending)
return callback(null, branch);
files.forEach(function(file) {
var concatPath = path.join(route, file);
fs.lstat(concatPath, function(err, stats) {
if (stats && stats.isDirectory()) {
getFolderContents(concatPath, function(err, res) {
branch.children.push(res);
if (!--pending)
callback(null, branch);
});
} else {
branch.children.push({
"title" : path.basename(file),
"path" : file
});
if (!--pending)
callback(null, branch);
}
});
});
});
}
感谢用户&#34; chjj&#34;他对这个帖子中的类似问题做出回应:node.js fs.readdir recursive directory search
感谢用户&#34; Dan Smolinske&#34;引导我到线程。