繁体   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