簡體   English   中英

擺脫貓鼬的藍鳥承諾鏈

[英]Break out of Bluebird promise chain in Mongoose

我已經研究了幾個相關的問題和答案,但仍然找不到我要解決的問題的解決方案。 我正在將貓鼬和藍鳥一起使用來承諾。

我的諾言鏈包括三個部分:

  1. 通過用戶名獲取用戶1

  2. 如果找到用戶1,請通過用戶名獲取用戶2

  3. 如果同時找到用戶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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM