2017-06-21 67 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 
    } 
}