如何停止嵌套回调和 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
循环,您可以 break
或 return
停止循环。
此外,由于您在循环内执行异步操作,因此您还需要使用 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);
})
所以目前我正在设置一个小的 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
循环,您可以 break
或 return
停止循环。
此外,由于您在循环内执行异步操作,因此您还需要使用 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);
})