繁体   English   中英

在 Node.js 中限制请求

[英]throttle requests in Node.js

我有一个数组。 我可以使用 foreach 方法遍历它。

data.forEach(function (result, i) {

     url = data[i].url;

     request(url);

});

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

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

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

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

谢谢你的帮助。

由于您的问题是全局性的,因此您应该调整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);
}
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
     );

 });

而不是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);

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

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

});

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

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

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

上述许多解决方案虽然适用于少数几个请求,但在处理成千上万个请求时,会不可避免地扼杀并整理页面。 不是将所有定时器排在一个,而是应该依次对每个定时器进行排序。 如果你的目标是拥有漂亮而又蓬松的代码以及大量的糖和'好吃的东西',那么下面就是你的解决方案。

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

这个问题的一些补充,只是为了知识库。

创建和异步版本没有递归。

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

将此代码放入 a.js 并调用如下:

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

使用 async / await 快速节流的一个非常简单的解决方案是创建一个承诺,例如:

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

然后在需要暂停时等待它(在async函数中):

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

注意:您需要使用for循环才能工作, forEach不会等待。

暂无
暂无

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

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