如何利用Async/Await与fs.readFile将文件内容存储到变量?
问题描述
以下是我的代码:
const fs = require('fs'); // const util = require('util'); let text = ``; const files = [`head.txt`,`body.txt`,`leg.txt`,`feet.txt`]; let head,body,leg,feet = ``; //const readFile = util.promisify(fs.readFile); function isCompleted(err,data) { if (err) { throw err; } text = data.toString(); proceedData() } function proceedData() { console.log(text); return text; } function readFileBody() { fs.readFile(files[1], 'utf8', isCompleted); } async function printFiles () { //head = await fs.readFile(files[0], 'utf8', (err,data) => {if (err) {throw err;}else {head += ` ${data}`}}); body = await readFileBody(); //await fs.readFile(files[2], 'utf8', isCompleted); //await fs.readFile(files[3], 'utf8', isCompleted); } printFiles();
遇到的问题:
- 在全局作用域中
console.log(body)时,返回undefined; - 在
printFiles函数内部(无return)console.log(body)时,同样返回undefined; - 但在
isCompleted函数内部console.log(text)能得到文件内容。
请问如何将文件内容存储到变量中?
解决方案
核心问题在于你混用了回调函数和async/await,而readFileBody函数并没有返回一个Promise,所以await readFileBody()根本不会等待文件读取完成就直接执行后续代码,导致body变量还没被赋值就被访问了。
下面给你几个清晰的改造方案:
方案1:使用fs.promises(推荐,现代Node.js原生支持)
Node.js从v10开始就内置了Promise化的fs API,直接用它可以避免回调地狱,完美配合async/await:
const fs = require('fs').promises; // 直接使用promises版本 const files = [`head.txt`,`body.txt`,`leg.txt`,`feet.txt`]; let head, body, leg, feet; async function printFiles () { // 按顺序读取文件并赋值给对应变量 head = await fs.readFile(files[0], 'utf8'); body = await fs.readFile(files[1], 'utf8'); leg = await fs.readFile(files[2], 'utf8'); feet = await fs.readFile(files[3], 'utf8'); // 现在可以正常访问这些变量了 console.log('body内容:', body); return { head, body, leg, feet }; } // 调用async函数需要处理Promise printFiles() .then(result => { console.log('所有文件内容:', result); // 这里也能访问全局变量或者result里的内容 }) .catch(err => console.error('读取文件出错:', err));
方案2:把readFileBody改造成返回Promise的函数
如果你不想用fs.promises,可以手动把回调式的函数包装成Promise:
const fs = require('fs'); const files = [`head.txt`,`body.txt`,`leg.txt`,`feet.txt`]; let body; // 包装readFile为返回Promise的函数 function readFileBody() { return new Promise((resolve, reject) => { fs.readFile(files[1], 'utf8', (err, data) => { if (err) { reject(err); // 出错时reject } else { resolve(data); // 成功时返回文件内容 } }); }); } async function printFiles () { body = await readFileBody(); console.log('body内容:', body); // 现在能正常打印了 } printFiles().catch(err => console.error(err));
方案3:使用util.promisify(兼容旧版Node.js)
你代码里注释掉了util.promisify,这也是一个把回调函数转成Promise的方法:
const fs = require('fs'); const util = require('util'); const readFile = util.promisify(fs.readFile); // 把fs.readFile转成Promise版本 const files = [`head.txt`,`body.txt`,`leg.txt`,`feet.txt`]; let body; async function printFiles () { body = await readFile(files[1], 'utf8'); console.log('body内容:', body); } printFiles().catch(err => console.error(err));
额外说明:为什么全局作用域打印body会是undefined?
因为printFiles是异步函数,它的执行不会阻塞主线程。当你在全局作用域打印body时,printFiles里的await readFileBody()还没执行完,文件内容还没赋值给body,所以自然是undefined。
如果要在全局作用域访问异步获取的内容,必须等待printFiles的Promise完成,比如用.then()或者在另一个async函数里等待它。
内容的提问来源于stack exchange,提问作者user8274065
相关产品推荐
相关产品推荐

