2017-06-21 66 views
0

我仍然試圖找到一種方法來處理循環中的承諾,並有條件地打破循環。如何有條件地處理帶有承諾的循環

下面是一個簡單的例子

return new Promise(function (resolve, reject) { 
        if (ipAddresses.length > 0) { 
         let currentServer, agentOptions; 
         for (let i = 0; i < ipAddresses.length; i++) { 
          currentServer = ipAddresses[i]; 
          agentOptions = { 
          }; 
          // We need to block here 
          let isReachable = NetworkUtils.checkIfReachable(agentOptions, ip); 
          if (isReachable) { 
           resolve(currentServer); 
           // Break out of the loop 
           return currentServer; 
          } 
          else { 
           // Continue looping and trying to find a working server 
          } 
         } 
         reject(new Error("No working servers found")); 
        } 
        else { 
         resolve(new Error("No servers ips provided")); 
        } 
       }) 

的問題是,我並不需要運行在平行謊言Promise.allasync.foreach所有要求,但我寧願要sequentually調用每一個承諾,如果條件爲真我需要打破這個循環,只要找到可以訪問的服務器,就不要再提出任何請求。

請建議什麼是正確的方式來處理這個用例。我一直在尋找很久,但還沒有找到任何好的解決方案。

感謝

編輯

對不起,是NetworkUntils.checkIfReachable()回報承諾

+2

是'NetworkUtils.checkIfReachable(agentOptions,IP)'同步的請求? – Hitmands

+0

我想['Promise.race()'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)就是你要找的東西。 –

+0

如果你「不需要像Promise.all那樣並行運行所有的請求」或者做異步請求,我問你爲什麼需要promise? – ranieribt

回答

3

假設NetworkUntils.checkIfReachable()實際上是異步的(這是在這個問題是有道理的和的NodeJS很可能是唯一上下文)和假設NetworkUntils.checkIfReachable()返回承諾或可以很容易地更改爲承諾,那麼您可以執行以下操作:

findFirstReachableServer(ipAddresses) { 
    if (!ipAddresses || !ipAddresses.length) { 
     return Promise.reject(new Error("No servers ips provided")); 
    } 
    let agentOptions = {...}; 
    let index = 0; 
    function next() { 
     if (index < ipAddresses.length) { 
      let ipAddress = ipAddresses[index++]; 
      return NetworkUtils.checkIfReachable(agentOptions, ipAddress).then(function(isReachable) { 
       if (!isReachable) { 
        return next(); 
       } else { 
        return ipAddress; 
       } 
      }) 
     } else { 
      return new Error("No working servers found"); 
     } 
    } 
    return Promise.resolve().then(next); 
} 

此函數返回一個承諾,如果找到可達的承諾,則使用ipAddress進行解析。如果沒有傳入地址,沒有找到可用地址或拒絕出於任何內部原因,它會拒絕。

請注意,要按順序運行非阻塞異步操作,您不能使用正常的for循環,因爲每個單獨的操作都不會阻塞,因此for循環不會等待它們(它只會運行到完成在任何操作完成之前)。因此,您必須使用不同的排序方法。有很多不同的方式來做到這一點。由於您不一定需要運行整個序列,因此我選擇了手動排序來控制是否調用下一次迭代。

+0

謝謝你的回答,我有你的想法,但它似乎與我在這個問題中描述的類似https://stackoverflow.com/questions/44675178/how-to-run-same-promises-one-after- another-nodejs 你能告訴我那裏的代碼有什麼問題嗎(請回答那個問題) – bxfvgekd

+2

@bxfvgekd - 我已經從頭寫過一個解決方案。爲什麼不使用這個?我真的不在乎第二次解決同樣的問題。僅供參考,您的其他解決方案有各種[承諾反模式](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns),所以我絕不會那樣做。 – jfriend00

0

給您所標記的問題,使用是不是一個壞主意確實:

async function findWorkingServer(ipAddresses) { 
    if (ipAddresses.length > 0) { 
     for (const currentServer of ipAddresses) { 
      const agentOptions = { … }; 
      const isReachable = await NetworkUtils.checkIfReachable(agentOptions, ip); 
//   We do "block" here ^^^^^ 
      if (isReachable) { 
       return currentServer; 
      } 
     } 
     throw new Error("No working servers found"); 
    } else { 
     return new Error("No servers ips provided"); // I think you meant to `throw` here 
    } 
}