2016-08-02 39 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