使用Promises纠正多路流的模式

时间:2016-11-03 22:10:48

标签: javascript promise es6-promise

所以我过去几天一直在玩承诺,只是尝试转换一些项目,使用承诺,但我已经多次担心这个问题。

在阅读文章和教程时,一切看起来都很流畅:

getDataFromDB()
.then(makeCalculatons)
.then(getDataFromDB)
.then(serveToClient)

但实际上,它不是那样的。
如果有条件,节目有很多"这改变了整个流程:

getDataFromCache(data).then(function(result){
    if(result){
        return result;
    }else{
        return getDataFromDB();
    }
}).then(function(result){
    if(result){
        serveToClient() //this does not return a promise, so undefined returned...
    }else{
        return getDataFromWebService(); //this does return a promise, 
    }
}).then(function(result){
    //i dont want to reach here if i already serveToClient()...
    //so i basically have to check "if(result)" for all next thens
    if(result){
       //do more stuff
    }
}).then(...

我有两个主要问题:

  1. 我发现自己在if回调中添加了很多then条件。
  2. 即使我已经完成(then
  3. ,我仍然会进入下一个serveToClient回调


    我是否遵循了正确的模式?

2 个答案:

答案 0 :(得分:5)

您无法避免if语句,因为逻辑流程需要这样做。如果您不想在if的某个部分继续保护链,则必须分支您的控制流。因此,如果在第二个.then()处理程序的某些部分,您不想继续使用第三个.then()处理程序,那么您需要像这样分支逻辑并放置后续{{1第二个.then()处理程序内部的处理程序在它们自己的逻辑分支中。

您不能继续使用顶级分支,因为在主链中中止未来.then()逻辑的唯一方法是拒绝承诺(您可能不想做) )或在每个.then()处理程序中添加另一个if检查,以决定是否应该跳过它(yuck)。

相反,您可以像这样分支逻辑:

.then()

您可能会发现这些其他答案很有用:

Understanding javascript promises; stacks and chaining

Is there a difference between promise.then.then vs promise.then; promise.then

仅供参考,你可以重新组织上面的代码,使其更简洁:

getDataFromCache().then(function(result){
    if(!result) {
        return getDataFromDB()
    } else {
        return result;
    }
}).then(function(result){
    // branch promise chain here into two separate branches
    if(result){
        // do not continue the promise chain here
        // call a synchronous operation
        serveToClient();
    } else {
        // continue promise chain here
        return getDataFromWebService().then(function(result) {
            if(result){
               //do more stuff
            }
        }).then(...);    // you can continue the promise chain here
    }
}).catch(function(err) {
    // process any errors here
});

答案 1 :(得分:2)

另一个答案解释了分支,但你也要求“顺利和干净”。

您可以使用ES6 arrow functions

getDataFromCache()
  .then(result => result || getDataFromDB())
  .then(result => result ? serveToClient() : getDataFromWebService()
    .then(result => { /* Won't reach here if serveToClient */ }))
  .then(() => { /* can continue promise chain here */ })
  .catch(e => console.log(e));

请注意,缩进的.then位于getDataFromWebService(),并且会看到尾部的双))。这很好地反映了同步分支。

您可以使用ES8 async / await(现已在Chrome CanaryFirefox Nightly中提供!):

try {
  if (await getDataFromCache() || await getDataFromDB()) {
    serveToClient();
  } else {
    let result = await getDataFromWebService();
    /* Won't reach here if serveToClient */
  }
  /* can continue here */
} catch (e) {
  // process any errors here
}

后者让你完全控制,好像事情是同步的,只要它在async functions内。