我试图在 forEach
循环完成向其中添加项目后返回一个数组。我尝试了几种方法,但它们都返回一个空数组或一个未解决的承诺。
class handleFiles {
constructor() {
this.promiseFiles = [];
this.promiseFolders = [];
}
async returnFilesAndFolders() {
fs.readdir("uploads", (err, files) => {
files.forEach((file) => {
if (fs.statSync(path.resolve(`uploads/${file}`)).isFile()) {
this.promiseFiles.push(file);
} else if (fs.statSync(path.resolve(`uploads/${file}`)).isDirectory()) {
this.promiseFolders.push(file);
} else {
}
});
});
let combined = {
sendFiles: Promise.all(this.promiseFiles),
sendFolders: Promise.all(this.promiseFolders),
};
return combined;
}
}
给班级打电话
app.get("/:dir?", (req, res) => {
let dir = req.params.dir;
console.log(dir);
let fileHandler = new handleFiles();
fileHandler.returnFilesAndFolders().then((data) => {
console.log(data);
res.render("index", {
data: data,
});
});
});
答案 0 :(得分:0)
您的原始实现有几个时间问题。您的 .forEach()
循环不会等待其中的任何异步操作完成,因此您最终会在数组填充之前调用 Promise.all()
。我建议使用具有内置承诺支持的 fs
操作,并且还使用带有 withFileTypes
的 fs.promises.readdir()
选项:
class handleFiles {
constructor() {
this.promiseFiles = [];
this.promiseFolders = [];
}
async getFilesAndFolders() {
let files = await fs.promises.readdir("uploads", {withFileTypes: true});
for (let file of files) {
if (file.isFile()) {
this.promiseFiles.push(file.name);
} else if (file.isDirectory()) {
this.promiseFolders.push(file.name);
}
}
return {
sendFiles: this.promiseFiles,
sendFolders: this.promiseFolders
}
}
}
注意:这个实现有点奇怪,因为它同时填充 this.promiseFiles
和 this.promiseFolders
,并且返回一个解析为包含该数据的对象的承诺。我真的建议你做一个或另一个。此外,由于添加到 this.promiseFiles
和 this.promiseFolders
的这种副作用编程,如果您多次调用 getFilesAndFolders()
,它将创建重复项。
也许你的实例数据中根本不需要这些数据,该方法可以只返回一个解析为对象的承诺:
class handleFiles {
constructor() {
}
async fillFilesAndFolders() {
const sendFiles = [], sendFolders = [];
let files = await fs.promises.readdir("uploads", {withFileTypes: true});
for (let file of files) {
if (file.isFile()) {
sendFiles.push(file.name);
} else if (file.isDirectory()) {
sendFolders.push(file.name);
}
}
return {
sendFiles,
sendFolders
};
}
}
但是,现在这只是一个与类没有任何关系的静态方法,所以它可能只是一个独立函数或静态方法。
第二个解决方案中的分步说明:
promiseFolders
和 promiseFiles
。await fs.promises.readdir()
以便我们可以使用 readdir
的 promise 接口。withFileTypes
选项,这样我们就可以访问 isFile()
和 isDirectory()
,而无需对每个文件进行额外调用。files
的列表并使用文件名填充所需的 promiseFiles
或 promiseFolders
数组。async
函数返回的 promise 的解析值。答案 1 :(得分:-2)
async returnFilesAndFolders() {
// Return the fs.readdir promise.
return fs.readdir("uploads").then((files) => {
// Collect the files into files and folders.
return files.reduce((acc, file) => {
// Get the status of the file.
const stat = fs.statSync(path.resolve(`uploads/${file}`));
if (stat.isFile()) {
acc.sendFiles.push(file);
}
elseif (stat.isDirectory()) {
acc.sendFolders.push(file);
}
return acc;
}, {sendFiles: [], sendFolders: []})
});
}
file
只是一个字符串,不是承诺,所以不需要解析。 fs.readdir
返回一个 promise,因此它可以与 .then
一起使用。进程退出时,中间的 promiseFiles 和 promiseFolders 将为空,但不需要它们,因为 file
不是承诺。