有一个函数,我可以用来读取目录中的所有文件,然后将带有发射器的对象发送给客户端。
这是我的代码,可以正常工作
const getFilesList = (path, emitter) => {
fs.readdir(path, (err, files) => {
emitter('getFileList', files);
});
};
但是当我想用此代码过滤隐藏文件时,“ standardFolders”将在发射器中发送为空。
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);
});
};
第二部分的代码有什么问题?
答案 0 :(得分:2)
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);
}
});
};
答案 1 :(得分:2)
在另一个答案中已经说过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
。