Node.js For循环在fs.readfile完成之前迭代

Node.js For循环在fs.readfile完成之前迭代,node.js,for-loop,Node.js,For Loop,预期行为:element.url[j]==url,因此会触发fs.readFile。最后,代码到达fs.writeFile并执行resolve(reply) 当前行为:代码按预期运行,直到fs.readFilefs.readFile开始同步运行,这意味着循环在内的代码块完成执行之前继续迭代。这会导致我的循环过早结束,因此当fs.writeFile完成并尝试执行resolve(reply)时,它不会执行任何操作,因为承诺已被拒绝(reply)在循环到达数组末尾时结束循环的末尾拒绝 这是我的代码,请

预期行为:
element.url[j]==url
,因此会触发
fs.readFile
。最后,代码到达
fs.writeFile
并执行
resolve(reply)

当前行为:代码按预期运行,直到fs.readFile
fs.readFile
开始同步运行,这意味着循环在内的代码块完成执行之前继续迭代。这会导致我的循环过早结束,因此当
fs.writeFile
完成并尝试执行
resolve(reply)
时,它不会执行任何操作,因为承诺已被
拒绝(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++;
    };
//循环监视并访问每个json的“URL”键
设i=0;
用于(监视器的let元素){
//检查url是否在数组中
对于(j=0;j{
console.log(“文件更新”);
让我们回答;
如果(错误){
//试图保存数据时出错
答复=[
{
“名称”:“试图从数组中删除url时出错”,
“值”:`错误:${err}`
}
];
//出口
拒绝(答复);
返回;
}
//成功
答复=[
{
“名称”:“已成功从数组中删除url”,
“value”:`我现在将停止监视提供的url`
},
{
“名称”:“项目名称”,
“价值”:项目
},
{
“名称”:“提供的URL”,
“值”:url
}
];
//出口
决议(答复);
返回;
});
});
}否则{
控制台日志(“监视器长度”);
console.log(monitor.length-1);
控制台日志(“i的值”);
控制台日志(i);
log(“元素长度URL”);
log(element.url.length-1);
控制台日志(“j值”);
控制台日志(j);
//检查这是否是最终迭代
if(i==monitor.length-1&&j==element.url.length-1){
控制台日志(“ugh”);
//这是最后一次迭代,提供的url不受bot监控
答复=[
{
“名称”:“机器人从未监视过该URL”,
“value”:`提供的URL不是bot当前监视的URL`
}
];
//出口
拒绝(答复);
返回;
}
}
}
console.log(“递增”);
//增量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
监视器长度
1.
i值
0
元素URL的长度
1.
j值
0
是,url在数组中
已从arrauy中删除url
递增
fs.readFile()
是非阻塞的。这意味着您的
for
循环将继续运行,同时从循环中启动所有
fs.readFile()
操作,并且这些操作将同时运行。然后,for
循环完成,有时您的
fs.readFile()
操作完成并调用回调,它们可以按任何顺序完成。因此,在您的
for
循环完成时,尚未调用任何
fs.readFile()
completion回调,并且可以按任何顺序调用它们。这应该可以解释你在输出中看到了什么

要使它们有序运行,最简单的方法是切换到使用Promission和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
循环结束时,所有异步操作都将完成

这使用
wait
for
循环中的异步操作进行排序,因此父函数必须标记为
async
,它将返回一个承诺,指示何时完成所有操作。

您可以使用同步方法