【问题标题】:How to handle for loop with promises conditionally如何有条件地处理带有 Promise 的 for 循环
【发布时间】:2017-11-24 16:07:45
【问题描述】:

我仍在尝试找到一种方法来有条件地处理循环中的承诺,并能够跳出循环。

这是一个简短的例子

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,但我需要依次调用每个承诺,如果条件为真,我需要打破循环并执行就我找到可访问的服务器而言,不要提出任何进一步的请求。

请提出处理此用例的正确方法。我一直在寻找很长时间,但仍然没有找到任何好的解决方案。

谢谢

编辑

抱歉,是的 NetworkUntils.checkIfReachable() 回报承诺

【问题讨论】:

  • NetworkUtils.checkIfReachable(agentOptions, ip) 是同步请求吗?
  • 我认为Promise.race() 是您正在寻找的。​​span>
  • 如果你“不需要像 Promise.all 那样并行运行所有请求”或者做异步请求,我问你为什么需要 Promise?
  • 您的代码似乎表明NetworkUtils.checkIfReachable() 是同步的(尽管这似乎不太可能)。如果它是同步的,那么你根本不需要承诺。你可以运行一个常规的for 循环并在找到答案时返回——没有承诺。如果NetworkUtils.checkIfReachable() 实际上是异步的,那么向我们展示它具有的异步接口,以便我们可以为它进行适当的编码。

标签: node.js asynchronous ecmascript-6 promise async-await


【解决方案1】:

鉴于您标记了问题,使用它确实不是一个坏主意:

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

【讨论】:

    【解决方案2】:

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

    这个函数返回一个promise,如果找到一个可达的,则用ipAddress 解析。如果没有传入地址、找不到可访问的地址或NetworkUtils.checkIfReachable() 出于任何内部原因拒绝,它会拒绝。

    注意,要按顺序运行非阻塞异步操作,您不能使用普通的for 循环,因为每个单独的操作都不会阻塞,因此for 循环不会等待它们(它只会在任何操作完成之前运行完成)。因此,您必须使用不同的排序方法。有很多不同的方法可以做到这一点。由于您不一定要运行整个序列,因此我选择了手动排序,您可以控制是否调用下一次迭代。

    【讨论】:

    • 谢谢你的回答,我明白你的想法,但它似乎与我在这个问题stackoverflow.com/questions/44675178/… 中描述的相似,你能告诉我我的代码有什么问题吗(请回答这个问题)
    • @bxfvgekd - 我已经从头开始为您编写了一个解决方案。为什么不只使用这个?我真的不在乎第二次解决同样的问题。仅供参考,您的其他解决方案有各种各样的promise anti-patterns in it,所以我永远不会那样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    • 1970-01-01
    • 2014-08-30
    相关资源
    最近更新 更多