[英]Break out of Bluebird promise chain in Mongoose
我已经研究了几个相关的问题和答案,但仍然找不到我要解决的问题的解决方案。 我正在将猫鼬和蓝鸟一起使用来承诺。
我的诺言链包括三个部分:
通过用户名获取用户1
如果找到用户1,请通过用户名获取用户2
如果同时找到用户1和用户2,则存储新记录
如果第1步或第2步都无法返回用户,则我不想执行第3步。但是,未能返回用户不会导致数据库错误,因此我需要手动检查有效用户。
我可以在步骤1中使用Promise.reject()
,它将跳过步骤2,但仍将执行步骤3。其他答案建议使用cancel()
,但我似乎也无法执行。
我的代码如下。 (我的函数User.findByName()
返回一个promise。)
var fromU,toU;
User.findByName('robfake').then((doc)=>{
if (doc){
fromU = doc;
return User.findByName('bobbyfake');
} else {
console.log('user1');
return Promise.reject('user1 not found');
}
},(err)=>{
console.log(err);
}).then((doc)=>{
if (doc){
toU = doc;
var record = new LedgerRecord({
transactionDate: Date.now(),
fromUser: fromU,
toUser: toU,
});
return record.save()
} else {
console.log('user2');
return Promise.reject('user2 not found');
}
},(err)=>{
console.log(err);
}).then((doc)=>{
if (doc){
console.log('saved');
} else {
console.log('new record not saved')
}
},(err)=>{
console.log(err);
});
您需要做的就是这样:
let findUserOrFail = name =>
User.findByName(name).then(v => v || Promise.reject('not found'));
Promise.all(['robfake', 'bobbyfake'].map(findUserOrFail)).then(users => {
var record = new LedgerRecord({
transactionDate: Date.now(),
fromUser: users[0],
toUser: users[1],
});
return record.save();
}).then(result => {
// result of successful save
}).catch(err => {
// handle errors - both for users and for save
});
您可以创建一个函数:
let findUserOrFail = name =>
User.findByName(name).then(v => v || Promise.reject('not found'));
然后您可以根据需要使用它。
例如,您可以这样做:
Promise.all([user1, user1].map(findUserOrFail)).then(users => {
// you have both users
}).catch(err => {
// you don't have both users
});
这种方式将更快,因为您不必等待第一个用户获得第二个用户-可以并行查询两个用户-并且将来可以将其扩展到更多用户:
let array = ['array', 'with', '20', 'users'];
Promise.all(array.map(findUserOrFail)).then(users => {
// you have all users
}).catch(err => {
// you don't have all users
});
无需使它复杂化。
将错误处理从内链移到要实际捕获/处理的位置。 由于我没有安装mongo,因此应使用以下伪代码来解决问题:
function findUser1(){
return Promise.resolve({
user: 1
});
}
function findUser2(){
return Promise.resolve({
user: 2
});
}
function createRecord(user1, user2){
return Promise.resolve({
fromUser: user1,
toUser: user2,
});
}
findUser1()
.then(user1 => findUser2()
.then(user2 => createRecord(user1, user2))) // better nest your promises as having variables in your outside scope
.then(record => console.log('record created'))
.catch(err => console.log(err)); // error is passed to here, every then chain until here gets ignored
通过将findUser1更改为
return Promise.reject('not found 1');
首先,我建议使用throw x;
而不是return Promise.reject(x);
,仅出于可读性原因。 其次,您的错误记录功能捕获了所有错误,这就是您的承诺链持续不断的原因。 尝试重新抛出错误:
console.log(err);
throw err;
不要在没有实际处理错误的情况下将错误记录放到任何地方-如果传递错误处理程序回调,您将获得一个承诺,该承诺将使用undefined
来实现,这不是您所需要的。 只需使用
User.findByName('robfake').then(fromUser => {
if (fromUser) {
return User.findByName('bobbyfake').then(toUser => {
if (toUser) {
var record = new LedgerRecord({
transactionDate: Date.now(),
fromUser,
toUser
});
return record.save()
} else {
console.log('user2 not found');
}
});
} else {
console.log('user1 not found');
}
}).then(doc => {
if (doc) {
console.log('saved', doc);
} else {
console.log('saved nothing')
}
}, err => {
console.error("something really bad happened somewhere in the chain", err);
});
这将始终记录“已保存”或“某事不好”消息之一,并且可能之前记录“未找到”消息之一。
您也可以使用异常来实现此目的,但实际上并没有变得更简单:
var user1 = User.findByName('robfake').then(fromUser => {
if (fromUser)
return fromUser;
else
throw new Error('user1 not found');
});
var user2 = user1.then(() => // omit this if you want them to be searched in parallel
User.findByName('bobbyfake').then(toUser => {
if (toUser)
return toUser;
else
throw new Error('user2 not found');
})
);
Promise.all([user1, user2]).then([fromUser, toUser]) =>
var record = new LedgerRecord({
transactionDate: Date.now(),
fromUser,
toUser
});
return record.save();
}).then(doc => {
if (doc) {
console.log('saved', doc);
} else {
console.log('saved nothing')
}
}, err => {
console.error(err.message);
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.