在链式承诺中,如果第一个承诺要求不执行其余的承诺,如何

时间:2016-09-27 11:54:43

标签: javascript promise

我有4个方法,每个方法都返回一个Promise,我将它们放在链式结构中。但是我没有在第一个Promise中有条件可以满足,所以在这种情况下我需要/不应该在链中执行剩余的Promise。我怎么能这样做?

这里有4项正在完成的任务

任务1)查看Mongo中是否存在数据,如果不存在

任务2)调用SOAP服务

任务3)使用SOAP的结果,操纵数据

任务4)将此文档放入Mongo

这很好,但是当任务1有数据时,我不应该处理下3个Promises(任务2,3,4)。

这是我目前的代码

checkMongoForData(req, res)
.then(function (result) {
   return makeTheSOAPcall(req, res, result)
.then(function (result) {
   return fillTheReasonDescriptions(req, res, result);
 })
 .then(function (result) {
   return upsertTheRespDocInMongo(req, res, result);
 })
 .then(function (result) {
   res.status(200);
   res.send({result: 'success', status: 200});
 })
 .catch(function (reject) {
   res.status(reject.status);
   res.send({result: reject.description, status: reject.status});
 });

//我的函数定义了类似这样的东西

function checkMongoForData(req, res) {
    return new Promise(function (resolve, reject) {
     // TODO : the logic goes here
     /// check to see for the data. If not there then continue
     // if there is data, no need to do remaining tasks
    });
 }

我如何实现这一目标?感谢。

3 个答案:

答案 0 :(得分:1)

  

我该怎么做?

制作checkMongoForData => getDataFromMongo并在没有数据时拒绝它。然后使用catch来捕获拒绝并触发获取数据的调用链:

getDataFromMongo(req, res)
    .catch(function() {
        // Didn't get the data, go get it
        return makeTheSOAPcall(req, res, result)
            .then(function (result) {
              return fillTheReasonDescriptions(req, res, result);
            })
            .then(function (result) {
              return upsertTheRespDocInMongo(req, res, result);
            });
    })
    .then(function (result) {
        // Got the data (one way or another)
        res.status(200);
        res.send({result: 'success', status: 200});
    })
    .catch(function (reject) {
        // Something went irretrievably wrong
        res.status(reject.status);
        res.send({result: reject.description, status: reject.status});
    });

如果upsertTheRespDocInMongo的分辨率值不是数据本身,您可能需要在其上添加.then来更改输出内容。

以下是一个例子:

var fakeMongo = Object.create(null);

function getDataFromMongo(key) {
    console.log("getDataFromMongo: ", key);
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            if (Object.prototype.hasOwnProperty.call(fakeMongo, key)) {
                // We have the data
                resolve({key: key, value: fakeMongo[key]});
            } else {
                // We don't have the data
                reject();
            }
        }, 100);
    });
}

function makeTheSOAPcall(key) {
    console.log("makeTheSOAPcall: " + key);
    return new Promise(function(resolve) {
        resolve({
            key: key,
            value: "value for " + key
        });
    });
}

function fillTheReasonDescriptions(result) {
    console.log("fillTheReasonDescriptions: " + result.key);
    return Promise.resolve(result);
}

function upsertTheRespDocInMongo(result) {
    console.log("upsertTheRespDocInMongo: " + result.key);
    return new Promise(function(resolve) {
        fakeMongo[result.key] = result.value;
        resolve(result);
    });
}

// Usage
retrieve("key1")       // Get key1 (won't be there)
  .then(function() {
    return retrieve("key2");  // Get key2 (won't be there)
  })
  .then(function() {   // Get key1 again (will be there)
    return retrieve("key1");
  })

function retrieve(key) {
    console.log("retrieve: " + key);
    return getDataFromMongo(key/*req, res*/)
        .catch(function() {
            // Didn't get the data, go get it
            return makeTheSOAPcall(key/*req, res*/)
                .then(function(result) {
                    return fillTheReasonDescriptions(/*req, res, */result);
                })
                .then(function(result) {
                    return upsertTheRespDocInMongo(/*req, res, */result);
                });
        })
        .then(function(result) {
            // Got the data (one way or another)
            console.log("Got the data:", result);
        })
        .catch(function(reject) {
            // Something went irretrievably wrong
            console.log("Somethingw went wrong", reject);
        });
}

答案 1 :(得分:1)

我喜欢ES6,因为我认为代码更具可读性。

var reply = msg => {
  res.status(msg.status);
  res.send(msg);
};

var fetchAndUpdate = result =>
  makeTheSOAPcall(req, res, result)
  .then(result => fillTheReasonDescriptions(req, res, result))
  .then(result => upsertTheRespDocInMongo(req, res, result));

checkMongoForData(req, res)
  .then(result => 
     //This is the key change.  If result is not enpty, then return a promise
     //resolve, else call fetchAndUpdate which returns a promise, which will.
     //be resolved (or rejected) eventually.
     result ? Promise.resolve() : fetchAndUpdate(result))
  .then(() => reply({result: 'success', status: 200}))
  .catch(e => reply({result: e.description, status: e.status}));

ES5

var reply = function(msg) {
  res.status(msg.status);
  res.send(msg);
};
var fetchAndUpdate = function(result) {
  return makeTheSOAPcall(req, res, result).then(function(result) {
    return fillTheReasonDescriptions(req, res, result);
  }).then(function(result) {
    return upsertTheRespDocInMongo(req, res, result);
  });
};
checkMongoForData(req, res).then(function(result) {
  return result ? Promise.resolve() : fetchAndUpdate(result);
}).then(function() {
  return reply({
    result: "success",
    status: 200
  });
}).catch(function(e) {
  return reply({
    result: e.description,
    status: e.status
  });
});

答案 2 :(得分:0)

一般来说,有多种方法可以解决这个问题。

其中一个是:

  • 在"四个任务链"
  • 之后使用额外的catch()
  • "拒绝" (但不是"错误")getDataFromMongo方法 现有数据(带有"虚拟"我们实际可以检查的错误 后)
  • "鸭打字"链条本身的拒绝原因

它不是最好的,但它不会破坏也不会显着改变你现有的承诺链(如果你愿意改变你的链条,你很可能会选择this answer by T.J. Crowder ):

// This can be anything, as long as it's "unique"
var dummyError = "has no data";

function checkMongoForData(req, res) {
    return new Promise(function (resolve, reject) {
        // TODO: Replace with your logic
        var hasData = false;
        var data = "";

        if (hasData) {
            resolve(data);
        } else {
            reject(dummyError);
        }
    });
}

checkMongoForData(req, res)
    .then(function (result) {
        return makeTheSOAPcall(req, res, result)
    })
    .then(function (result) {
        return fillTheReasonDescriptions(req, res, result);
    })
    .then(function (result) {
        return upsertTheRespDocInMongo(req, res, result);
    })
    .catch(function (error) {
        if (error === dummyError) {
            return;
        }

        // This line "re-throws"/"re-rejects" the error object
        return Promise.reject(error);
    })
    .then(function (result) {
        res.status(200);
        res.send({result: 'success', status: 200});
    })
    .catch(function (reject) {
        res.status(reject.status);
        res.send({result: reject.description, status: reject.status});
    });