简体   繁体   English

流星/ Node.js:在for循环中均匀地跨越一个定时间隔发出多个http请求?

[英]Meteor / Node.js: Multiple http requests within a for loop, evenly across a timed interval?

Dear fellow JS developers - 尊敬的JS开发人员-

I'm trying to make a batch of server-side http requests within a Meteor app on a timed interval and make updates to the MongoDB database based on the responses received. 我正在尝试按一定时间间隔在Meteor应用程序中发出一批服务器端http请求,并根据收到的响应对MongoDB数据库进行更新。 Every 15 seconds, the batch of requests should begin and the set of requests should be spread evenly across the 15 seconds (rather than flooding the API server all at once). 每隔15秒,应开始一批请求,并且该组请求应在15秒内平均分配(而不是一次淹没API服务器)。 To spread the requests evenly, I am attempting to use the setTimeout method. 为了平均分配请求,我尝试使用setTimeout方法。

There are two parameters that change between each http request, and these varying values are stored in two separate arrays. 每个http请求之间有两个参数更改,这些不同的值存储在两个单独的数组中。 Rather than spelling out each and every http request (if you count all the combinations between the two arrays, 20*4=80), I've written a for loop within a for loop to greatly consolidate the code. 而不是拼出每个HTTP请求(如果您计算两个数组之间的所有组合,即20 * 4 = 80),而是在for循环内编写了一个for循环,以极大地整合代码。 For each response, if it comes back OK, two switch statements handle how the response should be treated by evaluating it's i and y values. 对于每个响应,如果返回正常,则两个switch语句通过评估其iy值来处理应如何处理响应。

The problem: I seem to be in "callback hell". 问题:我似乎处于“回调地狱”中。 When the responses arrive from the server, the values of i and/or y sometimes have already been incremented by the loop system, so I cannot with 100% certainty handle the responses with the switch statements. 当响应从服务器到达时,循环系统有时已经将i和/或y的值增加了,因此我不能100%地确定使用switch语句来处理响应。 The updatedb() function ends up performing certain calculations on the wrong responses (storing them in the wrong places in the database). 最后, updatedb()函数对错误的响应进行了某些计算(将它们存储在数据库中的错误位置)。

Hoping someone can provide some guidance on what I can do differently to fix this as I'm at my wit's end. 希望有人能为我提供一些指导,以帮助我解决问题,因为我不知所措。

PS I tried doing this with a recursive approach but got a Maximum call stack size exceeded error. PS我尝试使用递归方法执行此操作,但出现了Maximum call stack size exceeded错误。




test = function test(){
  // API base URL
  var baseURL = "https://example.com/";
  // Array1
  var array1 =  ['item1', // i = 0
                 'item2', // i = 1
                 'item3', // i = 2
                 'item4', // i = 3
                 'item5', // i = 4
                 'item6', // i = 5
                 'item7', // i = 6
                 'item8', // i = 7
                 'item9', // i = 8
                 'item10', // i = 9
                 'item11', // i = 10
                 'item12', // i = 11
                 'item13', // i = 12
                 'item14', // i = 13
                 'item15', // i = 14
                 'item16', // i = 15
                 'item17', // i = 16
                 'item18', // i = 17
                 'item19', // i = 18
                 'item20']; // i = 19
  // Array2
  var array2 = ['/path1/',   // y=0
                '/path2/',   // y=1
                '/path3/',   // y=2
                '/path4/'];  // y=3

  var count = 1;
  var timeout = Math.round(interval/(array1.length*array2.length)*count);

  // Iterate over each item in array1
  Meteor.setTimeout(function() {
    for (i=0;i<array1.length;i++) {
      // Iterate over each path in array2
      for (y=0;y<array2.length;y++) {
        var request = Meteor.http.call("GET", baseURL + array1[i] + array2[y]);
        // If response is OK, then:
        if (request.statusCode == 200) {
          // do meaningful things
          function updatedb(value) {
            switch (y) {
              case 0: /*do something with uniqueValue for case of y=0 */; break;
              // case 1, case 2, case 3
            }
          }
          switch(i) {
            case 0: updatedb(uniqueValue); break;
            // case 1, case 2, case 3, case 4, case 5...
          }
        } else {
          throw new Meteor.Error(500, "API call failed with error: " + request.status_txt);
        }
      }
    }
  }, timeout);
  count++;
}

var interval = 15000;
Meteor.setInterval(function(){
  test();
}, interval);
for (i=0;i<array1.length;i++)

This is one of deadly sins in Javascript. 这是Javascript中的致命罪恶之一。 You declared a global variable i and iterate over that global variable. 您声明了一个全局变量i并对该全局变量进行迭代。 That way EVERY loop that iterates over i will iterate over THE SAME variable. 这样,每次迭代的循环i都将遍历SAME变量。 Not what you want I believe. 我不相信你想要的。

Rule of thumb: Always declare variables with var keyword. 经验法则: 始终使用var关键字声明变量。

(Exception: intentionally creating global variables.) (例外:故意创建全局变量。)

for (var i=0; i<array1.length; ++i)

Second problem with your code is more tricky, but fortunately well-known. 您的代码的第二个问题比较棘手,但幸运的是众所周知。 Look at this code: 看下面的代码:

var funs = [];

for(var y=0; y<10; ++y) {
  var print = function() {
    console.log(y);
  }
  funs.push(print);
}

for(var i=0; i<funs.length; ++i) {
  funs[i]();
}

What would you expect is printed to console when you run the code? 您希望在运行代码时将什么打印到控制台上? Think about it. 想一想。 Then check it out: http://repl.it/Uzb . 然后检查一下: http : //repl.it/Uzb

The second warning you see at that page says it all: Don't make functions within a loop . 您在该页面上看到的第二个警告说明了一切: 不要在循环内创建函数 What happens is that variable y you used inside the function body refers to the variable y scoped outside of the for block, which was already incremented to 10 by the time each of the function you've defined has been called. 什么情况是,可变y您使用里面的函数体是指可变y作用域之外for块,这是已经递增到10每个你定义已经被调用的函数的时间。 So console.log(y) always resolves to console.log(10) . 因此console.log(y)始终解析为console.log(10)

Rule of thumb: Don't make functions within a loop. 经验法则: 不要在循环内创建函数。

You can use an event on the element that gets updated after the call. 您可以在调用后对元素进行更新的事件上使用事件。

For an example you can look at http://test-this.ro/assign-the-same-tests-to-the-zephyr-suites-after-they-are-moved-to-another-project/ line #19 "$('body').on('requestscompleted', function(){..." 例如,您可以查看http://test-this.ro/assign-the-same-tests-to-the-zephyr-suites-after-they-moved-to-another-project/第19行“ $('body')。on('requestscompleted',function(){...”

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

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