【问题标题】:Correct pattern for multiway flows with Promises使用 Promise 的多路流的正确模式
【发布时间】:2017-03-17 15:54:12
【问题描述】:

所以过去几天我一直在使用 Promise,只是尝试转换一些项目以使用 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. 我发现自己在 then 回调中添加了很多 if 条件。
  2. 即使我已经完成了(serveToClient),我仍在进入下一个 then 回调


我是否遵循正确的模式?

【问题讨论】:

  • 尝试异步/等待,如果它变得更容易,在节点 7 中可用

标签: javascript promise es6-promise


【解决方案1】:

您无法避免 if 语句,因为这是您的逻辑流程所必需的。如果您不想在if 的一部分中继续承诺链,则必须分支您的控制流。因此,如果在第二个.then() 处理程序的某些部分,您不想继续使用第三个.then() 处理程序,那么您需要像这样分支逻辑并将后续.then() 处理程序放入第二个@987654328 @handler 在自己的逻辑分支中。

您不能只继续顶级分支,因为在主链中中止未来 .then() 逻辑的唯一方法是拒绝承诺(您可能不想这样做)或添加另一个 @987654330 @ 签入每个 .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
});

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

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)
        serveToClient();
    } else {
        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
});

【讨论】:

  • 添加了其他参考答案。
  • 嗯,我对这种方式的问题是随后的.then()。 Promise 的核心原因之一不就是避免回调金字塔吗?
  • @yosiweinreb - 您只需要逻辑所需的缩进级别。对于严格的顺序执行,您只需要一个长链并且不需要额外的嵌套。每次你想用if 语句分支你的链时,你必须添加一层嵌套。想一想,它与同步编程并没有什么不同。如果您在不想继续其余逻辑的同步编程中添加if,那么您也可以在其中添加一层嵌套。当你开始弄清楚如何处理错误情况时,promise 将比回调更好。
【解决方案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));

注意缩进的.thengetDataFromWebService() 上,并在尾部看到双))。这很好地反映了同步分支。

您可以使用 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 内部。

【讨论】:

  • 请注意,如果您不介意使用转译器,现在可以在生产环境中使用 async/await - 请参阅 babeljs.io
猜你喜欢
  • 2019-01-09
  • 2015-05-04
  • 2021-04-07
  • 1970-01-01
  • 2021-02-01
  • 1970-01-01
  • 2018-11-14
  • 2018-05-18
  • 2016-07-08
相关资源
最近更新 更多