【问题标题】:Need delay in between POSTs in JavaScript loop iterationsJavaScript 循环迭代中的 POST 之间需要延迟
【发布时间】:2014-10-09 10:31:28
【问题描述】:

我有一个 json 文件,我正在迭代它的内容,并为每次迭代使用一个 HTTP 发布请求。 POST 请求在数据库中插入信息。我需要在循环中或以某种方式在 POST 之间引入延迟。我现在拥有的是这样的:

var request = require('request');

for (i = 0; i < arr.length; i++) {
    request.post(
        'http://localhost:3000/post',
        { form: { from: arr[i][0], to: arr[i][1]} },
        function (error, response, body) {
            if (!error && response.statusCode == 200) {
                console.log(body)
            }
        }
    );
}

目前,POST 请求几乎是一个接一个地立即调用,这对一些需要一段时间的数据库插入逻辑造成了问题。有没有人知道如何实现延迟?

谢谢

【问题讨论】:

  • 我宁愿重写应用程序以支持完整的arr 请求。 (插入操作)。引入延迟似乎很老套
  • 我不会对可能起作用的延迟做出假设,而是使用回调或承诺并按顺序发布帖子
  • 查看我对 Johan 建议的回答。

标签: javascript node.js post get delay


【解决方案1】:

您遇到的问题是您正在混合同步(循环)和异步(请求)操作。

在继续下一次迭代之前,没有使外部循环等待内部异步操作完成的机制。

相反,您可以实现递归,要求回调函数启动外部“循环”的下一次迭代。

function do_post_req(arr_key) {
    request.post(
        'http://localhost:3000/post',
        { form: { from: arr[i][0], to: arr[i][1]} },
        function (error, response, body) {
            if (!error && response.statusCode == 200) {
                console.log(body);
                if (arr[key+1]) do_post_req(key+1); //<-- recursion
            }
        }
    );
}
do_post_req(0); //<-- kick things off with first array key

【讨论】:

  • +1,尽管您可能希望将递归调用移到 if 语句之外,以便在出现错误的情况下继续进行
  • 是的,我不确定 OP 是否想在出错时中断循环,所以我把它留给了他。
【解决方案2】:

也许使用setTimeout?不过,这似乎很hacky。

var interval = 10;
for (i = 0; i < arr.length; i++) {
    setTimeout(function() {
        request.post(
            'http://localhost:3000/post',
            { form: { from: arr[i][0], to: arr[i][1]} },
            function (error, response, body) {
                if (!error && response.statusCode == 200) {
                    console.log(body)
                }
            }
        );
    }, i * interval);
}

【讨论】:

    【解决方案3】:

    使用计时器:

    var interval = 1000;
    function doPosts() {
        if (arr.length == 0)
           return;
        data = arr.pop();
        request.post(
            'http://localhost:3000/post',
            { form: { from: data[0], to: data[1]} },
            function (error, response, body) {
                if (!error && response.statusCode == 200) {
                    console.log(body)
                }
            }
        );
        setTimeout(doPosts, interval);
    }
    doPosts();
    

    【讨论】:

      【解决方案4】:

      请查看节点 https://github.com/caolan/async#eacharr-iterator-callback 的异步模块

      添加手动休眠/等待是一个坏主意,因为回调总是有可能比您设置的手动时间更长或失败。

      var request = require('request');
      var async = require('async');
      
      async.each(arr, 
        function(arri, cb) {
           request.post(
              'http://localhost:3000/post',
              { form: { from: arri[0], to: arri[1]} },
              function (error, response, body) {
                  if (!error && response.statusCode == 200) {
                      console.log(body);
                      // do you insert stuff here before the cb() call so its done before the next request is executed
                      // if the insert stuff is asynchronous as well call cb() inside the callback of your insert
                      cb();
                  } else {
                      cb(error); // only do this if you want to stop at error
                  }
              }
          );
        }, 
        function(err) {
          if (err) { console.log(err); }
          else { console.log("all done"); }
        });
      

      如果您想并行运行请求,请查看异步的并行方法。

      【讨论】: