dav*_*vid 1 javascript node.js promise async-await node.js-fs
我正在尝试扫描本地目录以查找其中的所有文本文件,然后读取每个文件。我想使用 Promise、async 和 wait 来正确地完成它,但是出了问题,并且我一直在试图解决它。
我能够读取目录内容并正确输出所有文件名,但是当我尝试使用该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}`);
}
})();
Run Code Online (Sandbox Code Playgroud)
以下是该 javascript 的完整控制台输出,其中“Promise { }”日志被注释掉:
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
Run Code Online (Sandbox Code Playgroud)
我希望使工作解决方案尽可能接近此代码,因为它实际上是一个更大的难题的一部分,并且我需要能够继续利用此结构。
我的最终目标是读取所有这些文件,从中提取某些数据,然后将该数据写入新的 JSON 文件。
更新:检查下面的答案以获得问题的最准确的解决方案:/sf/answers/5264421571/
NodeJS 有 promisified 版本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}`);
}
})();
Run Code Online (Sandbox Code Playgroud)
如果您想修复原始代码,则需要进行一些更改。需要进行第一个更改,因为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);
});
});
};
Run Code Online (Sandbox Code Playgroud)
第二个改变是你的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';
};
Run Code Online (Sandbox Code Playgroud)
在原始代码中,您readFilePro为每个文件运行并检索一个永不等待的承诺。上面的方法解决了这个问题。
请让我知道这可不可以帮你。