我一直在寻找类似的问题,但似乎还没有找到一个对我来说很有效的解决方案。所以我正在开发一个Discord bot,它从MongoDB数据库中获取数据,并使用Mongoose以Discord嵌入消息的形式显示这些数据。大多数情况下,一切都很好,但是我的代码中有一小段给我带来了麻烦。所以我需要导入所有可用用户和每个用户的“时间”数据的数组。下面是我用来导入上述数据的代码块:
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
这个for循环引用了我制作的一个名为getData的函数,它通过以下方法从MongoDB获取数据:
async function getData(field, value){
var data;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
data = result[value];
}
});
if(field == "user"){
return data.user;
}else if (field == "time"){
return data.time;
}else{
return 0;
}
所以for循环就是我当前的错误所在。当我试图运行此代码并通过discord消息显示我的数据时,我会收到此错误并且消息没有被发送:
(节点:13936)UnhandledPromiserEjectionWarning:TypeError:无法读取未定义的属性“time”
现在奇怪的是,这种错误并不是每次都发生的。如果我继续调用从我的discord服务器触发这段代码的命令,如果命令实际上显示了消息或给出了这个错误,这几乎就像是一个50/50的机会。很不一致。
这个错误使我感到困惑,因为未定义的部分对我来说没有意义。在mongoDB集合中搜索的对象是明确定义的,for循环从不超过存在的对象数。我唯一的结论是,我的异步函数设计出了问题。我曾尝试修改代码,减少使用getData函数的次数,或者根本不使用等待或异步设计,但这留下了最后的不一致消息,其中包括几个未定义的变量和最终的崩溃。
如果任何人有任何意见或建议,那将非常感谢。仅供参考,下面是接收数据,对其进行排序并准备一个字符串以显示在discord服务器上的完整函数(尽管错误似乎只出现在第一个for循环中):
async function buildString(){
var string = "";
var totalObj;
var timeArray = [];
var userArray = [];
var stopSort = false;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
totalObj = result.length;
}
});
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
while(!stopSort){
var keepSorting = false;
for(i = 0; i < totalObj ; i++){
var target = await convertTime(timeArray[i]);
for(j = i + 1 ; j < totalObj ; j++){
var comparison = await convertTime(timeArray[j]);
if(target > comparison){
//Switch target time with comparison time so that the lower time is up front
var temp = timeArray[i];
timeArray[i] = timeArray[j];
timeArray[j] = temp;
//Then switch the users around so that the user always corresponds with their time
var userTemp = userArray[i];
userArray[i] = userArray[j];
userArray[j] = userTemp;
//The loop will continue if even a single switch is made
keepSorting = true;
}
}
}
if(!keepSorting){
stopSort = true;
}
}
//String building starts here
var placeArray = [':first_place: **1st', ':second_place: **2nd', ':third_place: **3rd', '**4th', '**5th', '**6th', '**7th', '**8th', '**9th', '**10th'];
for(i = 0; i < totalObj; i++){
string = await string.concat(placeArray[i] + ": " + userArray[i] + "** - " + timeArray[i] + " \n\n");
console.log('butt');
}
console.log("This String:" + string);
return string;
}
我认为问题是您试图用回调await
函数,它将不工作=>;对data.time
的访问可能在data=result[value]
之前运行。如果需要等待回调,可以使用自定义promise
(或使用util.promisify,此处提供更多信息)
承诺:
function findStats(options) {
return new Promise((resolve, reject) => {
return stats.find(options, function (err, result) {
if (err) {
return reject(err)
}
return resolve(result)
})
})
}
用途。允诺
const util = require('util');
const findStats = util.promisify(stats.find);
现在可以在函数中使用await
async function getData(field, value) {
try {
const result = await findStats({})
const data = result.value
if (field === 'user') {
return data.user
}
if (field === 'time') {
return data.time
}
return 0
} catch (error) {
// here process error the way you like
// or remove try-catch block and sanitize error in your wrap function
}
}