一旦你意識到.exec()
返回一個承諾,你可以:
- 達到預期的扁平化,使代碼更易讀。
- 避免需要處理「成功」代碼中的錯誤。
- 處理終端中的錯誤.then()或.catch()。
作爲一種獎勵,你也可以(更容易)爲每個x in y
條件投擲有意義的錯誤。
直截了當,你可以寫:
function _addFriend(requesterId, targetId) {
return User.findById(requesterId).exec().then(requester => {
if (targetId in requester.friends) {
throw new Error('target is already a friend');
}
if (targetId in requester.sentfriendRequests) {
throw new Error('friend request already sent to target');
}
if (targetId in requester.friendRequests) {
throw new Error('target already sent a friend request to requester');
}
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId]); // or just .push()?
return requester.save();
}).then(() => {
return User.findById(targetId).exec().then(target => {
target.friendRequests = target.friendRequests.concat([requesterId]); // or just .push()?
return target.save();
});
});
}
注需要返回到控制流量。
但你可以做得更好。正如上面所寫,被請求的東西可以成功,然後目標的東西失敗,導致數據庫差距。所以你真正想要的是一個db事務來保證兩者都發生或者兩者都不發生。無疑,Mongoose提供了交易,但是您可以在客戶端做一些事情,爲您提供部分利益的交易。
function _addFriend(requesterId, targetId) {
return Promise.all([User.findById(requesterId).exec(), User.findById(targetId).exec()]).then(([requester, target]) => { // note destructuring
if (targetId in requester.friends) {
throw new Error('target is already a friend');
}
if (targetId in requester.sentfriendRequests) {
throw new Error('friend request already sent to target');
}
if (targetId in requester.friendRequests) {
throw new Error('target already sent a friend request to requester');
}
requester.sentfriendRequests = requester.sentfriendRequests.concat([targetId]);
target.friendRequests = target.friendRequests.concat([requesterId]);
return requester.save().then(() => {
return target.save();
});
});
}
在這裏,你還可以得到(不太可能)的情況是,先救成功,第二保存失敗,但至少你有絕對什麼都不會發生,除非兩個請求者和目標存在的保證。
在這兩種情況下,請撥打如下:
_addFriend(requesterId, targetId).then(function() {
// do whatever on success
}, function(error) {
// do whatever on error
});
即使你沒有在現場環境中使用的錯誤信息,他們可以測試/調試時是非常有用的。請檢查他們 - 我可能弄錯了他們。
你確定第一個'exec'回調函數不需要'err'參數嗎? – Bergi
'.then(err => {if(err)throw err})'看起來不像應該需要承諾 – Bergi