node.js - For 循环在 fs.readfile 完成之前迭代
问题描述
预期行为:element.urls[j] == url
,因此fs.readFile
被触发。最终,代码到达fs.writeFile
并执行resolve(reply)
。
当前行为:代码按预期运行,直到fs.readFile
. fs.readFile
开始同步运行,这意味着循环在其中的代码块完成执行之前继续迭代。这会导致我的循环过早结束,因此 as fs.writeFile
is complete 并尝试执行resolve(reply)
,它什么也不做,因为 promise 已经被最后拒绝了reject(reply)
,一旦到达数组的末尾就结束循环。
这是我的代码,请见谅console.log()s
。正在使用它们进行调试:
//Loop through monitor and access the "urls" key of each json
let i = 0;
for (let element of monitor) {
//Checks if the url is in the array
for (j = 0; j < element.urls.length; j++) {
if (element.urls[j] == url) {
console.log("yes the url is in the array");
//The URL is in the array
let item = monitor[i].product;
//Removes the URL from the array
monitor[i].urls.splice(j, 1);
//Updates config.json with the new data
console.log("removed the url from the arrauy");
//Code splits into two branches here for some reason
fs.readFile('./config.json', function (err, data) {
console.log("file is opened time to update");
var json = JSON.parse(data);
json.monitor = monitor;
fs.writeFile("./config.json", JSON.stringify(json), (err) => {
console.log("file updated");
let reply;
if (err) {
//There was an error trying to save the data
reply = [
{
"name": "An error occured trying to remove the url from array",
"value": `Error: ${err}`
}
];
//Exit
reject(reply);
return;
}
//Success
reply = [
{
"name": "Successfully removed url from array",
"value": `I will now stop monitoring the url supplied`
},
{
"name": "Item name",
"value": item
},
{
"name": "URL supplied",
"value": url
}
];
//Exit
resolve(reply);
return;
});
});
} else {
console.log("monitor length");
console.log(monitor.length-1);
console.log("value of i");
console.log(i);
console.log("length of elements urls");
console.log(element.urls.length-1);
console.log("value of j");
console.log(j);
//Check if this is the final iteration
if (i == monitor.length-1 && j == element.urls.length-1) {
console.log("ugh");
//This is the last iteration, the url supplied is not monitored by the bot
reply = [
{
"name": "The bot was never monitoring that URL",
"value": `The URL supplied isn't one that the bot currently monitors`
}
];
//Exit
reject(reply);
return;
}
}
}
console.log("incrementing");
//Increment i
i++;
};
这是控制台输出,以便可以更好地可视化代码的路径:
monitor length
1
value of i
0
length of elements urls
1
value of j
0
yes the url is in the array
removed the url from the arrauy
incrementing <----- Shows that the loop is incrementing already
monitor length <----- Start of the loop again
1
value of i
1
length of elements urls
0
value of j
0
ugh
????? <----- Comes from outside the function, shows that the function this loop is in has already ended
file is opened time to update <----- This comes from after fs.writeFile() is done opening the file
file updated <----- fs.writeFile() is done saving the file to disk
如您所见,第一个循环被分解并fs.readFile()
同步运行。
非常感谢任何输入。在过去的几个小时里一直在这样做。
解决方案
fs.readFile()
是非阻塞的。这意味着您的for
循环继续运行,同时它fs.readFile()
从您的循环开始所有操作,并且它们都在同一时间进行中。然后,for
循环结束,有时稍后您的fs.readFile()
操作完成并调用它们的回调,它们可以按任何顺序完成。因此,在您的for
循环完成时,fs.readFile()
尚未调用任何完成回调,并且可以按任何顺序调用它们。这应该可以解释您在输出中看到的内容。
为了让它们按顺序运行,最简单的方法是切换到使用 Promise 和 readFile 的 Promise 接口。在结构上,这看起来像这样:
// function needs to be async
async function someFunction() {
for (...) {
try {
let data = await fs.promises.readFile(...);
// do something with data
} catch(e) {
// handle error
}
}
// all files have been processed here
}
这将按顺序处理您的文件,暂停for
循环,直到每个连续的 readFile() 完成并按顺序运行您的异步操作。而且,在for
循环结束时,所有异步操作都将完成。
这用于await
对for
循环中的异步操作进行排序,因此必须将父函数标记为async
,它将返回一个承诺,指示一切何时完成。
推荐阅读
- java - .read 错误:找不到符号符号:方法读取(缓冲读取器,
) 位置:jbutton 类型的变量 jtext1 - powershell - if($?) { } 是否有 powershell 模式
- javascript - 标记集群不起作用
- javascript - 图片显示一件事,但在加载网站时查询的数据显示另一件事
- python - 在python中跨平台清理表示为字符串的文件路径
- bash - 创建自定义随机变量
- django - Django会话:当用户不活动时断开连接
- flutter - 如何将渐变滤镜应用于图标?
- powerbi - Power M 函数将列的最常见字符串作为 Table.Group 聚合子句的一部分返回
- html - 链接以响应电子邮件