我试图扫描本地目录中的所有文本文件,然后读取每个文件。我想用promise, async和await来正确地完成它,但是有些东西出错了,我一直在试图找出它。
我能够正确读取目录内容并输出所有文件名,但是当我尝试使用map
方法读取这些文件本身时,我得到每个文件的Promise { <pending> }
日志。此外,我得到一个UnhandledPromiseRejection
错误在结束。
我可以在map
函数之外读取单个文件,但不能循环遍历所有文件并读取它们而不会出现错误。
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const textFileDir = `${__dirname}/files/`;
const readDirPro = (dir) => {
return new Promise((resolve, reject) => {
fs.readdir(dir, (error, files) => {
if (error) reject('Could not find directory');
resolve(files);
});
});
};
const readFilePro = (file) => {
return new Promise((resolve, reject) => {
fs.readFile(file, 'utf-8', (err, data) => {
if (err) reject('Could not find file');
resolve(data);
});
});
};
const readAllFiles = async () => {
try {
const dirFilesArr = await readDirPro(textFileDir);
// correctly outputs array of file names in directory
// console.log('dirFilesArr: ', dirFilesArr);
// THIS IS THE PROBLEM:
await dirFilesArr.map((file) => {
// console.log(file);
// correctly outputs filenames
const fileContent = readFilePro(file);
// console.log(fileContent);
// incorrectly outputs "Promise { <pending> }" logs for each file
});
} catch (err) {
console.log(`catch (err): ${err}`);
throw err;
}
return '2: final return';
};
(async () => {
try {
console.log('1: readAllFiles!');
const x = await readAllFiles();
console.log(x);
console.log('3: Done!');
} catch (err) {
console.log(`IIFE catch ERROR 💥: ${err}`);
}
})();
这是该javascript的完整控制台输出,注释掉了' Promise {} logs:
1: readAllFiles!
2: final return
3: Done!
node:internal/process/promises:289
triggerUncaughtException(err, true /* fromPromise */);
^
[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Could not find file".] {
code: 'ERR_UNHANDLED_REJECTION'
}
Node.js v19.0.1
我更喜欢保持工作解决方案尽可能接近这段代码,因为它实际上是一个更大的谜题的一部分,我需要能够继续利用这个结构。
我的最终目标是读取所有这些文件,从中提取某些数据,然后将这些数据写入新的JSON文件。
更新:下面是这个问题最准确的答案:https://stackoverflow.com/a/75206022/3787666
NodeJS有fs
的承诺版本,所以从技术上讲,你可以通过以下代码实现预期的结果:
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const textFileDir = `${__dirname}/files/`;
(async () => {
try {
console.log('1: readAllFiles!');
const dirFilesArr = await fs.promises.readdir(textFileDir);
const files = await Promise.all(dirFilesArr.map((file) => {
const fullPath = path.join(textFileDir, file);
return fs.promises.readFile(fullPath, { encoding: 'utf-8' });
}));
console.log(files);
console.log('3: Done!');
} catch (err) {
console.log(`IIFE catch ERROR 💥: ${err}`);
}
})();
如果你想修复你的原始代码,你需要做一些改变。首先需要进行更改,因为readdir
不返回具有完整路径的文件名,因此需要为每个文件添加路径以读取文件。因此,您的readFilePro
应该看起来像这样:
const readFilePro = (file) => {
return new Promise((resolve, reject) => {
fs.readFile(path.join(textFileDir, file), 'utf-8', (err, data) => {
if (err) reject('Could not find file');
resolve(data);
});
});
};
第二个更改是您的readAllFiles
需要更改如下:
const readAllFiles = async () => {
try {
const dirFilesArr = await readDirPro(textFileDir);
return Promise.all(dirFilesArr.map((file) => readFilePro(file)));
} catch (err) {
console.log(`catch (err): ${err}`);
throw err;
}
return '2: final return';
};
在您的原始代码中,您为每个文件运行readFilePro
并检索您从不等待的承诺。上面的方法解决了这个问题。
如果有帮助,请告诉我。
在上述公认答案的基础上,这里有一个补充答案,它解决了我问题的一个关键方面。而不是返回所有的数据在一个大块从map
,我真的需要能够操作数据从每个文件,只要它被读取(为什么我有const fileContent
在我上面的问题)。所以,这就是我现在如何处理,通过使用async/await
的回调在的map
方法。如果我想将const files
数据传递给Promise.all
之后的函数,我仍然需要Promise.all
方法和return
。
const files = await Promise.all(
dirFilesArr.map(async (file, i) => {
const fullPath = path.join(textFileDir, file);
const fileContent = await fs.promises.readFile(fullPath, {
encoding: 'utf-8',
});
//console.log(fileContent); // can now view file data individually
await externalFunction(fileContent, i); // manipulating file data
// return fs.promises.readFile(fullPath, { encoding: 'utf-8' });
})
);