如何停止嵌套回调和 foreach 循环中的代码?

How to stop code within nested callbacks and a foreach loop?

所以目前我正在设置一个小的 nodejs 数据库,我基本上是在尝试获取所有用户信息(如果用户存在)并执行回调 returning 用户信息,如果用户不存在那么我 return null。基本上,我的问题是,当我执行 return callback(null)return callback(userdata) 时,return 不会停止代码执行,导致执行 2 次回调和无效数据。这可能是由于这些 return callback() 嵌套在或 foreach 循环中的各种回调,尽管如果是这样,我不确定如何修复它。非常感谢任何帮助,谢谢!

代码如下:

const getUserInfo = (sessionToken, callback) => {
    return fs.readdir(__dirname + "/database/users", (err, files) => {
        if(err) return callback(null);
        return files.forEach((file, index) => {
            return fs.readFile(__dirname + "/database/users/" + file, "UTF-8", (err, data) => {
                if(err) return callback(null);
                try {
                    const parsedData = JSON.parse(data);

                    if(parsedData.sessionToken === sessionToken) return callback({ email: parsedData.email, username: parsedData.username, bought: parsedData.bought });
                    else if(index === files.length - 1) return callback(null);
                } catch {
                    return callback(null);
                }
            });
        });
    });
}

代码的一点解释:这是一个接受sessionToken的函数,sessionToken是用户当前会话的随机字符串,当然还有一个回调。然后它读取 database/users 目录以获取所有用户,然后对于该目录中的每个用户它读取文件并尝试通过 JSON 解析数据,如果它不起作用那么当然它returns null,如果它确实有效并且 sessionToken 匹配,那么它将使用所有必要的用户信息执行回调。如果我们到达列表的末尾并且 none 个会话匹配,那么我们得出用户不存在的结论。

不要使用 .forEach() 循环。请改用普通的 for 循环。 .forEach() 没有提供停止循环的方法。当您从 .forEach() 循环中 return 时,您只是从回调函数中 returning,而不是从父函数中 returning,因此无法停止循环或 return 来自 .forEach() 循环中的父函数。

使用常规 for 循环,您可以 breakreturn 停止循环。

此外,由于您在循环内执行异步操作,因此您还需要使用 let data = await fs.promises.readFile()(并使父函数 async)来对文件读取进行排序一个接一个地。否则,您所有的读取操作将并行进行,您将无法控制完成顺序。而且,如果你这样做了,你还不如 ​​return 你的函数对结果的承诺,而不是使用普通的回调函数。

这是一个示例实现:

const getUserInfo = async (sessionToken) => {
    let files = await fs.promises.readdir(__dirname + "/database/users");
    for (let file of files) {
        let data = await fs.promises.readFile(__dirname + "/database/users/" + file, "UTF-8");
        const parsedData = JSON.parse(data);
        if (parsedData.sessionToken === sessionToken) {
            return { email: parsedData.email, username: parsedData.username, bought: parsedData.bought };
        }
    }
    return null;
}

// usage
getUserInfo(token).then(val => {
    if (val) {
        console.log('Got user data', val);
    } else {
        console.log('User data not found');
    }
}).catch(err => {
    console.log(err);
})