简体   繁体   English

在 Node.js 中限制请求

[英]throttle requests in Node.js

I have an array.我有一个数组。 I can loop over it with the foreach method.我可以使用 foreach 方法遍历它。

data.forEach(function (result, i) {

     url = data[i].url;

     request(url);

});

The request function is making a http request to the given url.请求函数正在向给定的 url 发出 http 请求。 However making all these requests at the same time leads to all sorts of problems.然而,同时发出所有这些请求会导致各种问题。

So I thought I should slow things down by introducing some-sort of timer.所以我想我应该通过引入某种计时器来减慢速度。

But I have no idea how will be able to combine a forach loop with setTimeOut/setInterval但我不知道如何将 forach 循环与 setTimeOut/setInterval 结合起来

Please note am doing this on the server (nodejs) rather on the browser.请注意我是在服务器(nodejs)上而不是在浏览器上执行此操作。

Thanks for you help.谢谢你的帮助。

As your problem is global, you should adjust your request function to have only 5 request running at a time - using a global, static counter. 由于您的问题是全局性的,因此您应该调整request函数,以便一次只运行5个请求 - 使用全局静态计数器。 If your request was before something like 如果你的要求是在类似之前

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

now use something like 现在使用类似的东西

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

 });

Instead of setTimeout could have them run in sequence. 而不是setTimeout可以让它们按顺序运行。 I assume there's a callback parameter to your request() function. 我假设你的request()函数有一个callback参数。

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

makeRequest(data, 0);

If you need a little more time between requests, then add the setTimeout to the callback. 如果您在请求之间需要更多时间,则将setTimeout添加到回调中。

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

makeRequest(data, 0);

you can delay call using setTimeout. 你可以使用setTimeout延迟通话。 following code will insure that each request get called after timerMultiPlier milliseconds from its previous request. 以下代码将确保每个请求在其之前的请求之后的timerMultiPlier毫秒之后被调用。

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

});

You can the offset the execution delay of each item by the index, like this: 您可以通过索引来抵消每个项目的执行延迟,如下所示:

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

This will make each iteration execute about 100 milliseconds after the previous one. 这将使每次迭代在前一次迭代后执行约100毫秒。 You can change 100 to whatever number you like to change the delay. 您可以将100更改为您想要的任何数字以更改延迟。

Many of the above solutions, while practical for a few requests, unfourtunatly choke up and brick the page when dealing with tens of thousands of requests. 上述许多解决方案虽然适用于少数几个请求,但在处理成千上万个请求时,会不可避免地扼杀并整理页面。 Instead of queuing all of the timers at one, each timer should be qued sequentially one after another. 不是将所有定时器排在一个,而是应该依次对每个定时器进行排序。 If your goal is to have nice pretty fluffy code with lots of sugar and 'goodie-goodies' then below is the solution for you. 如果你的目标是拥有漂亮而又蓬松的代码以及大量的糖和'好吃的东西',那么下面就是你的解决方案。

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;
                }
            })();
        }
    };
}

Nice, pretty, fluffy sugar-coated usage: 漂亮,漂亮,蓬松的糖衣用法:

 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; } })(); } }; } 

Some addings to this questions, just for knowledge base.这个问题的一些补充,只是为了知识库。

Created and async version without recursion.创建和异步版本没有递归。

function onceEvery(msTime) {
  return {
    doForEach: function (eachFunc, paramArray) {
      var i = 0, Len = paramArray.length;
      (function rekurse() {
        if (i < Len) {
          eachFunc(paramArray[i], i, paramArray);
          setTimeout(rekurse, msTime);
          ++i;
        }
      })();
    },
    doForEachAsync: async function (eachFunc, paramArray, staticParamenters) {
      var i = 0, Len = paramArray.length;
      while (i < Len) {
        await (async function rekurse() {
          await eachFunc(paramArray[i], staticParamenters);
          setTimeout(() => { }, msTime);
          ++i;
        })();
      }
    }
  };
}

module.exports = {
  onceEvery
};

Put this code in a.js and call as simple as:将此代码放入 a.js 并调用如下:

await throttle.onceEvery(100).doForEachAsync(loadJobFunction, arrayParam, { staticParam1, staticParam2, staticParam3 });

a very simple solution for quick throttling using async / await is to create a promise such as:使用 async / await 快速节流的一个非常简单的解决方案是创建一个承诺,例如:

const wait = (delay) => new Promise((resolve, _) => {
  setTimeout(() => resolve(true), delay)
})

Then await for it when you need to pause (in an async function):然后在需要暂停时等待它(在async函数中):

  //... loop process
  await wait(100)

Note: you need to use a for loop for this to work, a forEach won't wait.注意:您需要使用for循环才能工作, forEach不会等待。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM