突破Mongoose的Bluebird承诺链

时间:2017-03-15 16:58:22

标签: javascript node.js mongodb mongoose promise

我研究过几个相关问题&答案,仍然无法找到我正在尝试做的解决方案。我正在使用Mongoose和Bluebird作承诺。

我的承诺链包含3个部分:

  1. 按用户名

  2. 获取用户1
  3. 如果找到了用户1,请按用户名

  4. 获取用户2
  5. 如果找到了用户1和用户2,则存储新记录

  6. 如果步骤1或步骤2无法返回用户,我不想执行步骤3.但是,如果未能返回用户,则不会导致数据库错误,因此我需要检查有效用户手动。

    我可以在步骤1中使用type TDatabaseRecord = class public ID: Integer; Name: String; end; function FindNameByID(ID: Integer): String; var I: Integer; begin Result := ''; for I := 0 to MyList.Count-1 do begin if TDatabaseRecord(MyList[I]).ID = ID then begin Result := TDatabaseRecord(MyList[I]).Name; Exit; end; end; end; ,它将跳过第2步,但仍会执行第3步。其他答案建议使用Promise.reject(),但我似乎也无法做到这一点。

    我的代码如下。 (我的函数cancel()返回一个承诺。)

    User.findByName()

4 个答案:

答案 0 :(得分:2)

实施例

你需要做的就是这样:

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'));

然后你可以按照自己的意愿使用它。

E.g。你可以这样做:

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
});

无需复杂化。

答案 1 :(得分:0)

将错误处理从内链移到您想要实际捕获/处理它的位置。由于我没有安装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');

答案 2 :(得分:0)

首先,我建议使用In [62]: df.groupby('id').head(1) Out[62]: summary id 183 12.0 11 14 6.0 17 4 6.0 18 代替throw x;,仅出于可读性原因。其次,您的错误记录功能会捕获所有错误,这就是您的承诺链继续存在的原因。尝试重新抛出错误:

return Promise.reject(x);

答案 3 :(得分:0)

不要将错误记录到任何地方而不实际处理错误 - 如果您传递错误处理程序回调,那么您将获得将履行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);
});