【问题标题】:throttle requests in Node.jsNode.js 中的限制请求
【发布时间】:2012-09-16 07:21:48
【问题描述】:

我有一个数组。我可以用 foreach 方法循环它。

data.forEach(function (result, i) {

     url = data[i].url;

     request(url);

});

请求函数正在向给定的 url 发出 http 请求。 但是同时提出所有这些请求会导致各种问题。

所以我想我应该通过引入某种计时器来减慢速度。

但我不知道如何将 forach 循环与 setTimeOut/setInterval 结合起来

请注意我在服务器 (nodejs) 上而不是在浏览器上执行此操作。

感谢您的帮助。

【问题讨论】:

  • 不完全是你想要的,但你可以尝试排队:github.com/caolan/async#queue。 IE 一次只能执行 10 个请求。
  • 各种问题”是什么意思?
  • @Bergi 在我自己的 nodejs 服务器上,任何“代理”都可以发出 5 个请求的默认限制。我可以增加,但我不想这样做。对于外部服务器,如果您发出大量并发请求,他们会切断您的联系。这就是我所说的“各种问题”。
  • @saeed:您的request() 函数是否接受回调。如果是这样,您不需要 setTimeout 来处理 5 个请求限制。只需按顺序运行它们,在前一个完成后执行下一个。
  • @user1689607 这意味着在收到 http 响应后继续执行。我认为这比设置计时器更复杂。

标签: javascript node.js settimeout throttling


【解决方案1】:

由于您的问题是全球性的,您应该调整您的 request 函数,使其一次只运行 5 个请求 - 使用全局静态计数器。如果您的请求是在类似

之前
function request(url, callback) {
    ajax(url, callback);
}

现在使用类似的东西

var count = 0;
var waiting = [];
function request(url, callback) {
    if (count < 5) {
        count++;
        ajax(url, function() {
            count--;
            if (waiting.length)
                request.apply(null, waiting.shift());
            callback.apply(this, arguments);
        });
    } else
        waiting.push(arguments);
}

【讨论】:

    【解决方案2】:
    data.forEach(function (result, i) {
    
         url = data[i].url;
    
         setTimeout(
             function () {
                  request(url);
             }, 
             1000 * (i + 1) // where they will each progressively wait 1 sec more each
         );
    
     });
    

    【讨论】:

      【解决方案3】:

      可以让它们按顺序运行,而不是setTimeout。我假设您的 request() 函数有一个 callback 参数。

      function makeRequest(arr, i) {
          if (i < arr.length) {
              request(arr[i].url, function() { 
                                      i++; 
                                      makeRequest(arr, i); 
                                  });
          }
      }
      
      makeRequest(data, 0);
      

      如果您在请求之间需要更多时间,请将setTimeout 添加到回调中。

      function makeRequest(arr, i) {
          if (i < arr.length) {
              request(arr[i].url, function() { 
                                      i++; 
                                      setTimeout(makeRequest, 1000, arr, i); 
                                  });
          }
      }
      
      makeRequest(data, 0);
      

      【讨论】:

        【解决方案4】:

        您可以使用 setTimeout 延迟通话。以下代码将确保每个请求在其上一个请求的timerMultiPlier 毫秒后被调用。

        var timerMultiPlier = 1000;
        data.forEach(function (result, i) {
             setTimeout(function(){
                   url = data[i].url;         
                   request(url);
           }, timerMultiPlier*i );
        
        });
        

        【讨论】:

          【解决方案5】:

          您可以通过索引来抵消每个项目的执行延迟,如下所示:

          data.forEach(function (result, i) { 
            setTimeout(function() {
              url = data[i].url; 
              request(url);
            }, i * 100);
          }); 
          

          这将使每次迭代在前一次迭代之后大约 100 毫秒执行。您可以将100 更改为您想要更改延迟的任何数字。

          【讨论】:

            【解决方案6】:

            上述许多解决方案虽然对少数请求很实用,但在处理数以万计的请求时却不幸地阻塞并阻塞了页面。与其将所有计时器排在一个队列中,不如将每个计时器一个接一个地依次排入队列。如果您的目标是编写包含大量糖和“好东西”的漂亮蓬松代码,那么以下是适合您的解决方案。

            function miliseconds(x) { return x }
            function onceEvery( msTime ){
                return {
                    doForEach: function(arr, eachF){
                        var i = 0, Len = arr.length;
                        (function rekurse(){
                            if (i < Len) {
                                eachF( arr[i], i, arr );
                                setTimeout(rekurse, msTime);
                                ++i;
                            }
                        })();
                    }
                };
            }
            

            漂亮、漂亮、蓬松的糖衣用法:

            onceEvery(
                miliseconds( 150 )
            ).doForEach(
                ["Lorem", "ipsum", "dolar", "un", "sit", "amet"],
                function(value, index, array){
                    console.log( value, index );
                }
            )
            
            function miliseconds(x) { return x }
            function onceEvery( msTime ){
                return {
                    doForEach: function(arr, eachF){
                        var i = 0, Len = arr.length;
                        (function rekurse(){
                            if (i < Len) {
                                eachF( arr[i], i, arr );
                                setTimeout(rekurse, msTime);
                                ++i;
                            }
                        })();
                    }
                };
            }

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-18
              • 2016-10-29
              • 1970-01-01
              • 2020-12-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-03-23
              相关资源
              最近更新 更多