我是Node / Mongoose的新手,正在尝试正确处理脚本中的错误以将玩家添加到联赛中。在下面的代码中,.catch()语句正确捕获了显式引发的和与Promise不相关的错误,但是被拒绝的Promise却没有。
例如,尝试传递无效的用户ID会抛出User not found
。
但是,如果我通过断开数据库测试Promise拒绝,则会得到以下信息:
(node:6252) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoNetworkError: failed to connect to server [localhost:27017] on first connect [MongoNetworkError: connect ECONNREFUSED 127.0.0.1:27017]
我不正确地使用Promise.all()和.catch()吗?
为了清楚起见,我试图弄清楚为什么不处理错误,而不是为什么引发错误。
我的脚本:
const
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
mongoose.connect(dbUrl, { useNewUrlParser: true });
const addUserToLeague = (userId, leagueId) => {
let foundUser = User.findById(userId);
let foundLeague = League.findById(leagueId);
return Promise.all([foundUser, foundLeague])
.then(arr => {
if(!arr[0]){
throw 'User not found';
}else if(!arr[1]){
throw 'League not found';
}
return arr;
})
.then(arr => {
arr[0].leagueMemberships.push(arr[1]);
arr[1].users.push(arr[0]);
return arr;
})
.then(updatedArr => {
updatedArr[0].save();
updatedArr[1].save();
return updatedArr;
})
.then(updatedArr => { console.log(`User ${updatedArr[0]._id} added to league ${updatedArr[1]._id}`) })
.catch(err => { console.log('Error:', err) });
};
addUserToLeague(process.argv[2], process.argv[3]); // Needs 2 args: User ID and League ID
答案 0 :(得分:2)
正如Bergi指出的那样,错误似乎来自connect
,而您根本没有处理returns a promise,包括没有等待它完成。因此,至少需要处理以下问题:
const connectionPromise = mongoose.connect(dbUrl, { useNewUrlParser: true })
.catch(error => {
// Handle connection error
});
然后在addUserToLeague
中输入
const addUserToLeague = (userId, leagueId) => {
return connectionPromise.then(connection => {
// ...logic here
});
};
... 但是,我质疑在这样加载模块时是否应该连接,而不是将连接传递到addUserToLeague
。
除此之外,Promise.all
的实际使用还可以,但是:
findById
不会在没有找到该项目的情况下用假的值来解决承诺,因此整个第一个then
处理程序似乎都是不必要的。 / li>
save
返回一个诺言。您不会处理拒绝或等待解决的情况。arr[0]
和arr[1]
,因为很容易忘记顺序。then
调用的push
处理程序与进行保存的then
处理程序分开。addUserToLeague
应该返回promise链的结果,以便调用它的代码A)知道何时完成,B)知道何时失败。addUserToLeague
中处理错误;而是在调用方中处理它们。addUserToLeague
中的代码中可以清楚地看出原因:如果保存用户成功但保存联盟失败怎么办?然后,用户对象说它是联赛的成员,而联赛对象没有说它是联赛的成员。还有一个问题是,由于它存储在两个地方,即使没有问题,在很短的时间内,其中一个(用户或联盟)将被保存,而另一个则不会被保存。两者都是完整性问题。如果您可以将其标准化为将此信息存储在一个地方,那将是很好的。如果不能,则需要更新代码,以便保存其中的一个,等待代码成功,再保存另一个,如果失败,则尝试撤消对第一个所做的更改。类似这样的东西(我不试图在这里解决规范化问题,这是一个大图景):
const
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
const addUserToLeague = (connection, userId, leagueId) => {
return Promise.all([
User.findById(userId),
League.findById(leagueId)
])
.then(([user, league]) => {
user.leagueMemberships.push(league);
league.users.push(user);
return Promise.all([user.save(), league.save()]);
})
.then((([user, league]) => {
console.log(`User ${user._id} added to league ${league._id}`);
});
};
mongoose.connect(dbUrl, { useNewUrlParser: true })
.then(connection => addUserToLeague(connection, process.argv[2], process.argv[3]) // Needs 2 args: User ID and League ID
.catch(error => {
// Handle/report error
});
如果您正在使用Node的最新版本,则可以使用async
函数:
const
mongoose = require('mongoose'),
User = require('./models/users'),
League = require('./models/leagues'),
dbUrl = process.env.DBURL || 'mongodb://localhost/predictor';
const addUserToLeague = async (connection, userId, leagueId) => {
let [user, league] = await Promise.all([
User.findById(userId),
League.findById(leagueId)
]);
user.leagueMemberships.push(league);
league.users.push(user);
[user, league] = await Promise.all([user.save(), league.save()]);
console.log(`User ${user._id} added to league ${league._id}`);
};
mongoose.connect(dbUrl, { useNewUrlParser: true })
.then(connection => addUserToLeague(connection, process.argv[2], process.argv[3]) // Needs 2 args: User ID and League ID
.catch(error => {
// Handle/report error
});