2016-08-02 80 views
1

我找到了“The Ghost Promise”here这个词,看起来像我的情况。如何解决诺言反模式 - 鬼诺言?

我有这样的代码:

return Q.Promise(function(resolve, reject) { 
    firstFunctionThatReturnPromise() 
    .then(function(firstResult) { 
    _check(firstResult) ? resolve(firstResult) : return secondFunctionThatReturnPromise(); 
    }) 
    .then(function(secondResult) { 
    console.log(secondResult); 
    return thirdFunctionThatReturnPromise(secondResult); 
    }) 
    .then(function(thirdResult) { 
    resolve(thirdResult); 
    }) 
    .catch(function(e) { 
    reject(e) 
    }); 
}); 

的问题是,即使_check返回true,但它仍然继续到console.log命令(导致undefined)。

如果_check返回false,则事情按预期工作。

所以我的问题是:

  • 如果上述行为是正常的吗?
  • 如果有更优雅的方式来处理这种情况?

更新1:很多质疑我为什么用Q.Promise,而不是结果直接返回。这是因为这是一个通用函数,由其他函数共享。

// Usage in other functions 
genericFunction() 
.then(function(finalResult) { 
    doSomething(finalResult); 
}) 
.catch(function(err) { 
    handleError(err); 
}); 
+0

你这里没有鬼,但是一个普通的['Promise' constructor antipattern](http://stackoverflow.com/q/23803743/1048572)! – Bergi

回答

2

首先,没有理由围绕这些做出新的承诺。你的行动已经回复了承诺,所以它是一个error prone anti-pattern重新包装在一个新的承诺。

第二关,正如其他人所说,一个.then()处理程序有以下选择:

  1. 它可以返回将被传递到下一个.then()处理结果。没有返回任何东西通过undefined到下一个.then()处理程序。
  2. 它可以返回一个promise,它的解析值将被传递给下一个.then()处理程序,或者被拒绝的值将被传递给下一个拒绝处理程序。
  3. 它可以抛弃它将拒绝当前的承诺。

没有从.then()处理方式告诉一个承诺链有条件地跳过不是拒绝其它一些下列.then()处理程序。

所以,如果你想根据一些条件逻辑分支你的诺言,那么你需要根据你的分支逻辑实际上巢您.then()处理程序:

a().then(function(result1) { 
    if (result1) { 
     return result1; 
    } else { 
     // b() is only executed here in this conditional 
     return b().then(...); 
    } 
}).then(function(result2) { 
    // as long as no rejection, this is executed for both branches of the above conditional 
    // result2 will either be result1 or the resolved value of b() 
    // depending upon your conditional 
}) 

所以,当你想分支,你可以创建一个新的嵌套链,让你控制基于条件分支的事情。

使用你的伪代码,它会是这个样子:

firstFunctionThatReturnPromise().then(function (firstResult) { 
    if (_check(firstResult)) { 
     return firstResult; 
    } else { 
     return secondFunctionThatReturnPromise().then(function (secondResult) { 
      console.log(secondResult); 
      return thirdFunctionThatReturnPromise(secondResult); 
     }) 
    } 
}).then(function (finalResult) { 
    console.log(finalResult); 
    return finalResult; 
}).catch(function (err) { 
    console.log(err); 
    throw err; 
}); 

即使这是一个genericFunction里面,你仍然可以只返回你已经有了承诺:

function genericFunction() { 
    return firstFunctionThatReturnPromise().then(function (firstResult) { 
     if (_check(firstResult)) { 
      return firstResult; 
     } else { 
      return secondFunctionThatReturnPromise().then(function (secondResult) { 
       console.log(secondResult); 
       return thirdFunctionThatReturnPromise(secondResult); 
      }) 
     } 
    }).then(function (finalResult) { 
     console.log(finalResult); 
     return finalResult; 
    }).catch(function (err) { 
     console.log(err); 
     throw err; 
    }); 
} 

// usage 
genericFunction().then(...).catch(...) 
+0

感谢您的回答,我编辑我的问题添加我使用承诺包装的原因。 – haipham23

+1

@ haipham23 - 我仍然没有看到任何理由在承诺中包装这个。你似乎并不明白你不需要为了回报而做出新的承诺。按照我的答案显示,您可以返回已有的。 – jfriend00

+0

谢谢,我遵循上面的指示,它完美的作品! – haipham23

0

我从来没有使用Q,但一切承诺返回转化为一个承诺,并传递到下一个.then()。在这里,你的第一个.then()不会返回任何东西。所以它返回undefined。所以undefined被封装在一个新的Promise并传递到下一个处理程序,在那里你得到secondResult == undefined

你可以看到它在行动以下CodePen:http://codepen.io/JesmoDrazik/pen/xOaXKE

1

行为的预期。当你链接你的陈述时,除了抛出一个错误之外,你不能早早脱离链条。

您的顶级承诺(由Q.Promise()返回的承诺)将在_check()后得到解决;但你实际上有一个持续执行的内部承诺链。

通过规范,then()返回一个承诺:https://promisesaplus.com/#point-40

可以在Q的源代码中看到自己:https://github.com/kriskowal/q/blob/v1/q.js#L899

对于您所期望的行为,你实际上需要另一个嵌套承诺链。

return Q.Promise(function(resolve, reject) { 
    firstFunctionThatReturnPromise().then(function(firstResult) { 
    if (_check(firstResult)) { 
     resolve(firstResult); 
    } else { 
     return secondFunctionThatReturnPromise().then(function(secondResult) { 
     console.log(secondResult); 
     return thirdFunctionThatReturnPromise(secondResult); 
     }); 
    } 
    }); 
}); 
+2

鉴于所有函数已经返回promise,所以不需要用'Q.Promise'来包装它们。只需返回'firstFunctionThatReturnPromise'返回的诺言(并简单地返回'firstResult',因为它会自动换行)。 – robertklep