有一个函数,我用它来读取目录中的所有文件,然后将带有发射器的对象发送到客户端。
这是我的代码,工作正常,
const getFilesList = (path, emitter) => {
fs.readdir(path, (err, files) => {
emitter('getFileList', files);
});
};
但是当我想使用此代码过滤隐藏文件时,"标准文件夹"将在发射器中发送空。
const getFilesList = (path, emitter) => {
let standardFolders = [];
fs.readdir(path, (err, files) => {
if (files) {
files.map((file) => {
winattr.get(path + file, function (err, attrs) {
if (err == null && attrs.directory && (!attrs.hidden && !attrs.system)) {
standardFolders.push(file)
}
});
});
} else {
standardFolders = null;
}
emitter('getFileList', standardFolders);
});
};
我在第二部分中的代码有什么问题?
winattr.get(filepath,callback)
是异步的,所以想象一下你的代码"开始"file.map()
行,然后立即跳到emitter('getFileList',standardFolders)
---哪个standardFolders
是空的,因为它还没有完成!
您可以使用像 async.io 这样的库来处理回调函数,也可以使用计数器并跟踪所有回调(针对每个文件)何时完成。
例:
// an asynchronous function because setTimeout
function processor(v,cb){
let delay = Math.random()*2000+500;
console.log('delay',delay);
setTimeout(function(){
console.log('val',v);
cb(null,v);
},delay);
}
const main = function(){
const list = ['a','b','c','d'];
let processed = [];
let count = 0;
console.log('starting');
list.map(function(v,i,a){
console.log('calling processor');
processor(v,function(err,value){
processed.push(v);
count+=1;
console.log('count',count);
if(count>=list.length){
// all are finished, continue on here.
console.log('done');
}
})
})
console.log('not done yet!');
};
main();
同样,对于您的代码:
const getFilesList = (path, emitter) => {
let standardFolders = [];
fs.readdir(path, (err, files) => {
if (files) {
let count = 0;
files.map((file) => {
winattr.get(path + file, function (err, attrs) {
if (err == null && attrs.directory && (!attrs.hidden && !attrs.system)) {
standardFolders.push(file)
}
count+=1;
if(count>=files.length){
// finally done
emitter('getFileList', standardFolders);
}
});
});
} else {
standardFolders = null;
emitter('getFileList', standardFolders);
}
});
};
正如在另一个答案中已经说过的winattr.get
是异步的,因此循环在调用winattr.get
的任何回调之前完成。
您可以使用async
/await
和primitify
将代码转换为看起来几乎像同步版本的代码,并且可以完全摆脱回调或计数器
const {promisify} = require('util')
const readdir = promisify(require('fs').readdir)
const winattrget = promisify(require('winattr').get)
const getFilesList = async (path, emitter) => {
let standardFolders = [];
try {
let files = await readdir(path);
for (let file of files) {
try {
let attrs = await winattrget(path + file)
if (attrs.directory && (!attrs.hidden && !attrs.system)) {
standardFolders.push(file)
}
} catch (err) {
// do nothing if an error occurs
}
}
} catch (err) {
standardFolders = null;
}
emitter('getFileList', standardFolders);
};
附加说明:在您的代码中,您编写files.map
,但映射用于转换给定数组的值并将它们存储在新数组中,这在您当前的代码中没有完成,因此在给定的情况下,您应该使用 forEach
循环而不是 map
。