如何使用 Promises 有条件地执行第二个任务?

How do I conditionally perform a second task using Promises?

我正在使用 Bookshelf.js,一个基于 Promise 的 ORM 模块,来执行几个数据库查找。给定用户提供的密钥,我需要确定该密钥是否与两个 table 之一中的记录匹配。如果我在第一个 table 中找到它,我需要 return 那个记录。但是,如果我在第一个 table 中找不到它,我需要在第二个 table 中查找。基本上,我需要有条件地执行一个 then 块。我如何使用承诺来完成这个?这是我目前拥有的,非常混乱,事实上,我有点不清楚如果我在第一个 School 查找中调用 resolve 会发生什么——第二个 then 块也执行?

exports.findTargetRecord = function(code){

    return new Promise(function(resolve, reject){
        Schools
        .query({ where: { code: code }})
        .fetchOne()
        .then(school => {
            if(school) return resolve(school);
            return Organizations
                    .query({ where: { code: code }})
                    .fetchOne();
        })
        .then(org => {
            if(org) return resolve(org);
            resolve(null);
        })
        .catch(err => reject(err));
    });
};

有没有更简洁的写法?

您可以将整个 else 逻辑保留在 then 块中:

exports.findTargetRecord = function(code){

    return new Promise(function(resolve, reject){
        Schools
        .query({ where: { code: code }})
        .fetchOne()
        .then(school => {
            if(school) return resolve(school);
            return Organizations
                    .query({ where: { code: code }})
                    .fetchOne()
                    .then(org => {
                        if(org) return resolve(org);
                        resolve(null);
                    })
        })
        .catch(err => reject(err));
    });
};

此外,您的代码可以像这样重写(较短的版本):

exports.findTargetRecord = function(code){
    return Schools
            .query({ where: { code: code }})
            .fetchOne()
            .then(school => {
                if(school) return school;
                return Organizations
                        .query({ where: { code: code }})
                        .fetchOne();
            })
            .catch(err => reject(err));

使用 promises 作为代理和常规 if:

exports.findTargetRecord = function(code){

  const school = Schools.query({ where: { code: code }}).fetchOne();
  school = school.then(school => 
    school || Organizations.query({ where: { code: code }}).fetchOne())
  return school;
}

或者使用 bluebird 支持的协程(bluebird 附带书架):

exports.findTargetRecord = Promise.coroutine(function*(code) {
   var school = yield Schools.query({ where: { code: code }}).fetchOne();
   if(school) return school;
   return Organizations.query({ where: { code: code }}).fetchOne();
});