2016-11-03 83 views
6

所以我一直在玩承諾的最後幾天,只是試圖轉換一些項目,使用承諾,但超過了幾次我已經把這個問題包攬了。

在閱讀文章和教程,一切看起來光滑潔淨:承諾多路流的正確模式

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(... 

我有2個主要問題:

  1. 我發現自己增加對then回調if條件很多。
  2. 我仍然得到進入下一個then回調,即使我已經完成(serveToClient


我是按照正確的方式?

+0

嘗試異步/等待,如果它變得更容易,節點7中可用 – Endless

回答

5

您無法避免if語句,因爲這是您的邏輯流程所必需的。如果您不想在if的某個部分繼續承諾鏈,您將必須分支您的控制流程。因此,如果在第二個處理器的某個部分中,您不想繼續處理第三個.then()處理程序,那麼您需要分支這樣的邏輯,並將後續的.then()處理程序放入處理程序的第二個處理程序的自己的分支中邏輯。

您不能繼續頂級分支,因爲在主鏈中中止未來.then()邏輯的唯一方法是要麼拒絕承諾(您可能不想這麼做),要麼添加另一個if檢查每個.then()處理程序來決定是否應該跳過(yuck)。

因此,相反,你可以分支這樣的邏輯:

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 
}); 

您可能會發現這些答案有用:FYI

Understanding javascript promises; stacks and chaining

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


,你可以重新組織上面的代碼更加合作ncise是這樣的:

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 
}); 
+0

添加其他參考答案。 – jfriend00

+0

那麼我的問題是隨後的'.then()'。是不是Promise的核心原因之一是避免回調金字塔? – yosiweinreb

+2

@yosiweinreb - 您只需要按照您的邏輯要求儘可能多的縮進級別。對於嚴格的順序執行,您只需要一條長鏈並且不需要額外的嵌套。每當你想用if語句分支你的鏈時,你都必須添加一層嵌套。想想看,這與同步編程沒有任何區別。如果在同步編程中添加一個不希望繼續邏輯其餘部分的'if',那麼您也可以在其中添加一層嵌套。當你開始研究如何處理錯誤情況時,承諾將大大優於回調。 – jfriend00

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

+1

請注意,如果您不介意使用轉譯器,可以在今天的製作中使用'async/await' - 請參閱http://babeljs.io/。 –