【问题标题】:http.get request loop closure issue (Node)http.get 请求闭环问题(节点)
【发布时间】:2015-03-23 17:22:25
【问题描述】:

我希望能够在命令行中输入一系列 URL,并按照提供的顺序获取请求的结果。我已经研究了闭包来实现这一点,因为回调不会按顺序执行(更有可能是哪个响应最快)

for (var i = 2; i < process.argv.length; i++) {
  (function(index) {
    http.get(process.argv[index], function (response) {
      response.pipe(bl(function (err, data) {
        console.log(data.toString());
      }));
    });
  })(i);
}

参数上的 for 循环。然后每次迭代调用 IIFE 匿名函数,该函数又调用 get 请求等等。 但是问题仍然存在,它是乱序执行的。不是按照用户要求的顺序。

我做错了什么?

【问题讨论】:

    标签: node.js loops get request closures


    【解决方案1】:

    如果您只是尝试按顺序记录结果,但希望请求并行运行,那么通常的解决方案是将结果收集到一个数组中,然后在所有请求时输出结果完成了。

    var count = process.argv.length - 2;
    var results = new Array(count);
    for (var i = 2; i < process.argv.length; i++) {
      (function(index) {
        http.get(process.argv[index], function (response) {
          response.pipe(bl(function (err, data) {
            results[index - 2] = data.toString();
            --count;
            if (count === 0) {
                for (var j = 0; j < results.length; j++) {
                    console.log(results[j]);
                }
            }
          }));
        });
      })(i);
    }
    

    这种蛮力方法也可以稍微聪明一点,以便在此之前的所有请求都完成时更快地输出结果,而不是等待所有请求完成。

    另一种方法是对每个请求使用 Promise,然后使用 Promise.all() 等待所有异步操作完成,Promise.all() 也会为您收集所有结果。

    而且,像 Async 这样的 nodejs 库也有很多功能可以管理大量异步操作。


    如果你想序列化请求实际上会简单一些(只有在前一个请求完成时才启动下一个请求)。可以这样做:

    function runAll() {
        var index = 2;
        function next() {
            if (index < process.argv.length) {
                http.get(process.argv[index], function (response) {
                    response.pipe(bl(function (err, data) {
                        console.log(data.toString());
                        ++index;
                        next();
                    }));
                });
            }
        }
        next();
    }
    

    而且,这里有一个使用 Promise 的版本,它并行运行请求,但按顺序返回结果:

    var Promise = require('bluebird');
    
    function runAll() {
        var promises = [];
        for (var i = 2; i < process.argv.length; i++) {
            promises.push(new Promise(function(resolve, reject) {
                http.get(process.argv[index], function (response) {
                    response.pipe(bl(function (err, data) {
                        resolve(data.toString());
                    }));
                });
            }));
        }
        return Promise.all(promises);
    }
    
    runAll().then(function(resultArray) {
        // resultArray contains an array of the results from all the operations, in order
        for (var i = 0; i < resultArray.length; i++) {
            console.log(resultArray[i]);
        }
    });
    

    【讨论】:

    • 那个版本很简单。这是非常可读的。您的阵列解决方案也很有趣。我不知道用闭包但不使用数组是不可能做到的。
    • 一般有没有办法控制回调?我的意思是不使用第三方模块。我认为关闭是答案。在这种情况下,使用闭包似乎对我没有帮助,而且我知道我做错了。
    • @yahimeh - 我为你编写了两个答案。 Promise 内置在 ES6 中(或者您现在可以获取一个库来使用它们),这将是另一种方式。不知道你还想要什么。我的两种解决方案都使用了闭包 - 您只是没有使用正确的方法。
    • @yahimeh - 我添加了第三个版本,它使用了 Promise,这是我通常处理此类问题的方式。
    猜你喜欢
    • 2016-04-25
    • 2018-09-25
    • 2020-06-08
    • 2018-05-04
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多