我正在尝试使用&#f;'来制作文件资源管理器。 Node.js的模块。
我编写了以下函数,它接受一个路径并将该路径(文件/文件夹)的内容存储在一个数组中,然后使用回调函数将其发回。
listDir: function (path, myCallback) {
var resultObj = [];
fs.readdir(path, function (err, data) {
console.log('In listDir');
if (err) {
return myCallback(err, null);
} else {
data.forEach(function (value) {
fs.lstat(path + '/' + value, function (err, stats) {
if (err) {
console.log(err);
} else {
//console.log('Size-' + stats.isFile()+'\n');
if(stats.isFile()){
//console.log('is file----\n');
/*resultObj.push({
type: 'file',
name: value,
size: stats['size']
});*/
resultObj.push(value);
console.log(resultObj+'\n');
} else if(stats.isDirectory()){
//console.log('is folder----\n');
/*resultObj.push({
type: 'folder',
name: value,
size: stats['size']
});*/
resultObj.push(value);
console.log(resultObj+'\n');
}
}
});
});
console.log('Resultant obj-' + resultObj);
return myCallback(null, resultObj);
}
});
}
对于存储在'数据'中的每个文件/文件夹,我试图检查它是文件还是文件夹,并根据我想要将对象推入我的&#39 ; resultObj'阵列。 但是,返回语句甚至在forEach完成之前就会执行,因此每次都会得到一个空的resultObj。
为什么会这样?为什么即使我提供了回调函数,它也会异步运行?
当我使用路径参数调用/ test路径时输出是这样的 -
在listDir中
结果obj-
GET / test?path = F:\ dummyFolder 304 15.210 ms - -
文件1
文件1,文件2
文件1,文件2,folder3
请帮助我,我真的坚持这项必须在今晚完成的任务。并且在分配中明确提到不使用“fs”的任何同步功能。 MODULE 即可。 那么我怎么能记住这个条款?
PS:不要介意评论,我用它们进行调试。
答案 0 :(得分:0)
问题在于您没有等待fs.lstat()
功能完成每个文件。您排队等待所有fs.lstat()
次来电,但不等待所有这些电话完成。当它仍为resultObj
时,您才会返回[]
。
您可以通过在data.forEach()
的回调中添加一项检查来解决此问题,以查看有多少项目已调用fs.lstat()
的回调。
listDir: (path, myCallback) => {
let resultObj = [];
fs.readdir(path, (err, data) => {
console.log('In listDir');
if (err) {
return myCallback(err);
}
let itemsCompleted = 0
data.forEach(value => {
fs.lstat(path + '/' + value, (err, stats) => {
itemsCompleted++
if (err) {
console.log(err);
} else {
if(stats.isFile() || stats.isDirectory()){
resultObj.push(value);
console.log(resultObj+'\n');
}
}
if(itemsCompleted >= data.length) {
return myCallback(null, resultObj)
}
});
});
}
然而,上述方法仍然比使用async/await
的Promises更复杂。使用async/await
的promise是当前处理Node中异步控制流的首选方法。利用util.promisify()
来宣传fs.readdir()
和fs.lstat()
,可以让我们扁平化控制流,并显着提高listDir()
的可读性。此外,通过使用map()
代替forEach()
,我们可以使用Promise.all()
为每个条目包装返回的Promise lstatAsync()
。
const {promisify} = require('util')
const fs = require('fs')
const {join} = require('path')
const readdirAsync = promisify(fs.readdir)
const lstatAsync = promisify(fs.lstat)
module.exports = {
listDir: async path => {
let resultObj = [];
let entries = await readdirAsync(path)
console.log('In listDir');
await Promise.all(entries.map(async value => {
try {
let stats = await lstatAsync(join(path, value))
if(stats.isFile() || stats.isDirectory()){
resultObj.push(value);
console.log(resultObj+'\n');
}
} catch (err) {
console.log(err)
}
}))
return resultObj
}
}