我是javascript的新手,所以如果以前有人问我这个问题,我很抱歉。
我有这个函数,我用它来读取json文件。
const jsonfile = require('jsonfile');
function readData(fileName: string, callback) {
jsonfile.readFile(".\data\" + fileName + ".json", 'utf8', function (err, data) {
if (err) console.error(err)
callback(null, data);
})
}
然后我用这个来称呼它:
// Read JSON files
var fileList = ["guides"];
var files = {};
for (let i = 0; i < fileList.length; i++) {
readData(fileList[i], function (err, result) {
if (err) throw err;
files[i] = result;
})
}
但当我:
console.log(files['guides']);
则返回CCD_ 1。有人能帮我解决这个问题吗?非常感谢。
jsonfile.readFile
函数的回调函数被异步调用,并且console.log
语句被同步执行。
异步代码在javascript代码的同步执行结束后执行;因此,在files
对象中添加guides
属性之前,console.log
语句正在记录files['guides']
。这就是为什么你没有定义。
下面的代码示例显示了这个问题的作用:
let a = 1;
setTimeout(() => {
a = 2;
}, 100);
console.log(a);
上面的代码段输出1
,因为setTimeout
的回调函数是异步调用的,即在执行了undefined
0语句之后的,并且在执行console.log
语句时,a
的值为1
。
解决方案
为了确保在读取所有文件并填充files
对象之后记录files["guides"]
,可以从readData
函数返回promise。
以下代码展示了如何围绕readData
函数创建promise包装器:
function readData(fileName) {
return new Promise((resolve, reject) => {
jsonfile.readFile(".\data\" + fileName + ".json", 'utf8', function (err, data) {
if (err) reject(err);
else resolve(data);
})
}
};
现在您可以将上述函数调用为:
Promise.all(fileList.map(filePath => readData(filePath)))
.then(dataFromAllFiles => {
console.log(dataFromAllFiles);
})
.catch(error => console.log(error));
有用链接:
异步JavaScript
Promises 的优雅异步编程
使用Promises