[英]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.