繁体   English   中英

在for循环中发送post请求

[英]Sending post request in for loop

我想循环发送帖子请求。 如果我连续发送2个请求,那么只有最后一个请求真正进行了回调。

我做错了什么?

this.assignAUnits = function(){
        var currentIncidentId = this.incident.incidentId;
        for (var i=0; i< this.selectedAvailableUnits.length; i++){
            var unit = this.selectedAvailableUnits[i];
            var unitId = unit.unitId;

            var url = '/incident/' + currentIncidentId + '/assignUnit/' + unitId

            $http.post(url).then(function(response) {
               DOING SOMETHING

            }, function(error) {
                alert(error);
            });          
        }
    };

使用closure 让我举个简单的例子

// JavaScript on Client-Side
window.onload = function() {
    var f = (function() {
        for (i = 0; i < 3; i++) {
            (function(i){
                var xhr = new XMLHttpRequest();
                var url = "closure.php?data=" + i;
                xhr.open("GET", url, true);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState == 4 && xhr.status == 200) {
                        console.log(xhr.responseText); // 0, 1, 2 
                    }
                };
                xhr.send();
            })(i);
        }
    })();
};

// Server-Side (PHP in this case)
<?php 
    echo $_GET["data"];
?>

在你的情况下...用一个闭包来包装异步调用/函数

for (var i=0; i< this.selectedAvailableUnits.length; i++) {

    (function(i) {    // <--- the catch

        var unit = this.selectedAvailableUnits[i];
        var unitId = unit.unitId;
        var url = '/incident/' + currentIncidentId + '/assignUnit/' + unitId
        $http.post(url).then(function(response) {
            // DOING SOMETHING
        }, function(error) {
            alert(error);
        });

    })(i);    // <---- (the i variable might be omitted if it's not needed)

}

以下部分与问题没有直接关系,而是与此答案相关的评论。


在评论中提到的jsFiddle提交的示例如下所示是错误的,因此它没有任何证据。

确实,这个片段,即使不使用封闭,也会产生三次“Hello Kitty”; 实际上,如果用一个alert()替换console.log()方法,你会看到它产生'Hello Kitty'六,九,甚至十二次。 那么,到底是怎么回事;)如何在三次迭代的循环中让警报窗口弹出六次,九次或十二次?!

// your example (a)                                   // my comments 
//
var f = (function() {
    for (i = 0; i < 3; i++) {
        //(function(){                                // this way you can't have multiple scopes 
            var xhr = new XMLHttpRequest();
            var url = "closure.php?data=your-data";   // use /echo/html/ for testing on jsfiddle.net
            xhr.open("GET", url, true);               // use POST for testing on jsfiddle.net 
            xhr.onreadystatechange = function () {    // this way you might catch all readyStage property values
                callback();                           // this way the callback function will be called several times
            };
            xhr.send();
        //})();
    }
})();

var callback = function() {
    console.log("Hello Kitty"); // or use alert("Hello Kitty");
};

输出:

GET http://fiddle.jshell.net/_display/closure.php?data=your-data 404 (NOT FOUND) 
(9) Hello Kitty

正如你所看到的,我们有一个错误和连续九个'Hello Kitty'输出:)在我改变上面的功能之前让我们看看两个重要的事情

第一

onreadystatechange事件存储每次readyState属性更改时自动调用的函数或引用,而status属性保存XMLHttpRequest对象的状态。

readyState属性可能的值

  • 0:请求未初始化
  • 1:建立服务器连接
  • 2:收到请求
  • 3:处理请求
  • 4:请求完成并且响应准备就绪

status属性可能的值

  • 200:好的
  • 404页面不存在

第二

正如我在评论中所说,如果没有一些更改,jsfiddle.net对于测试异步代码段是不可靠的。 换句话说,应该将GET方法更改为POST并且必须将url属性更改为此链接/echo/html/ (有关更多选项,请查看jsFiddle文档

现在,让我们改变上面的例子(并按照代码中的注释)

// corrected example (b)
//
var f = (function() {
    for (i = 0; i < 3; i++) {
        //(function(i){                                              // uncomment this line for the 3rd output                               
            var xhr = new XMLHttpRequest();
            var url = "/echo/html";
            var data = "data";
            xhr.open("POST", url, true);
            xhr.onreadystatechange = function () {
                //if (xhr.readyState == 4 && xhr.status == 200) {    // uncomment this line for the 4th output
                    callback(i, xhr.readyState);                     // uncomment this line for the 4th output
                //}
            };
            xhr.send(data);
        //})(i);                                                     // uncomment this line for the 3rd output
    }
})();

var callback = function(i, s) {
    console.log("i=" + i + " - readyState=" + s + " - Hello Kitty");
};

第一输出://六输出

(4) i=3 - readyState=1 - Hello Kitty    // four outputs related to readyState value 'server connection established'
    i=3 - readyState=2 - Hello Kitty    // related to readyState value 'request received'
    i=3 - readyState=4 - Hello Kitty    // related to readyState value 'request finished and response is ready'

第二输出://六输出

(2) i=3 - readyState=1 - Hello Kitty    // two outputs related to readyState value 'server connection established'
    i=3 - readyState=2 - Hello Kitty    // related to readyState value 'request received'
(3) i=3 - readyState=4 - Hello Kitty    // three outputs related to readyState value 'request finished and response is ready'

如果没有在例子(b)中做出任何改变,我们有两个不同的输出。 如您所见,不同readyState属性值的不同输出已经产生。 i的价值保持不变。

第3个输出://取消注释示例(b)中上面显示的第3个输出的行

i=0 - readyState=2 - Hello Kitty        // related to readyState value 'request received'
i=0 - readyState=4 - Hello Kitty        // related to readyState value 'request finished and response is ready'
i=1 - readyState=2 - Hello Kitty        // ...
i=1 - readyState=4 - Hello Kitty        // ... 
i=2 - readyState=2 - Hello Kitty
i=2 - readyState=4 - Hello Kitty

因此,在取消注释将i作为参数的函数后,我们看到i的值已被保存。 但这仍然是不正确的,因为有六个输出,我们只需要三个。 因为我们不需要XMLHttpRequest对象的readyStatestatus属性的所有值,所以让我们取消注释第四个输出所需的两行

第4个输出://取消注释示例(b)中上面显示的第4个输出的行 - 最后是三个输出

i=0 - readyState=4 - Hello Kitty
i=1 - readyState=4 - Hello Kitty
i=2 - readyState=4 - Hello Kitty 

最后,这应该是片段的正确版本,这就是我们需要的。

另一个全能的,无所不能的机制(正如我之前所说的那样)将是bind()函数,我不喜欢它,因为它比闭包慢。

对不起,我不使用angularjs,但这两个使用jQuery或甚至基于XMLHttpRequest的方法对我来说效果很好:

<button onclick="sendWithJQuery()">send</button>
<ul id="container"></ul>
<script src="/vendor/bower_components/jquery/dist/jquery.js"></script>
<script>
  //use XMLHttpRequest
  function send(){
      for (var i = 1; i <= 10; i++){
          var xhr = new XMLHttpRequest();
          xhr.open('POST', '/test/' + i);
          xhr.onreadystatechange = function(){
              if (this.readyState != 4){
                  return;
              }
              var li = document.createElement('li');
              li.appendChild(document.createTextNode('client time:' + new Date().toISOString() + ', data: ' + this.responseText));
              container.appendChild(li);
          }
          xhr.send();
      }
  }

  //use jQuery
  function sendWithJQuery(){
      for (var i = 1; i <= 10; i++){
          $.ajax({
          url: '/test/' + i,
          method: "POST",
          statusCode: {
              200: function (data, textStatus, jqXHR) {
                  var li = document.createElement('li');
                  li.appendChild(document.createTextNode('client time:' + new Date().toISOString() + ', data: ' + JSON.stringify(data)));
                  container.appendChild(li);
              },
              500: function (data, textStatus, jqXHR) {
                  alert('Internal server error');
              }
          }
      });
      }
  }
</script>

服务器代码(nodejs):

router.post('/test/:i', function(req, res) {
    var i = req.params.i;
    var t = new Date().toISOString();
    setTimeout(function(){
        res.send({i: i, t: t});
    }, 1000);
});

你试图在for-loop使用一个变化的变量url

如果你不在循环中使用闭包,只有你的for的最后一个值将进入$http.post调用。
循环内部的闭包可能是一个棘手的野兽。 看到这个问题JavaScript封闭内部循环 - 简单实用的例子和谷歌它更多的理论/细节。

您的代码必须以这样的方式进行调整:

var doPost = function(url) {

  $http.post(url).then(
    function(response) {
      // DOING SOMETHING
    },
    function(error) {
      alert(error);
    });

}

this.assignAUnits = function(){
        var currentIncidentId = this.incident.incidentId;
        for (var i=0; i< this.selectedAvailableUnits.length; i++){
            var unit = this.selectedAvailableUnits[i];
            var unitId = unit.unitId;

            var url = '/incident/' + currentIncidentId + '/assignUnit/' + unitId

            doPost(url)
        }
    };

编辑:附加参考
我不久前有一个非常类似的问题,你可以在这里阅读: Angular JS - $ q.all()跟踪个人上传进度

这显然是一个封闭问题。 在这里阅读更多

此外,建议使用超过$ http的$ resource。 (NG-资源)。

查看使用资源发布for循环的示例。

      for(var i=0; i<$scope.ListOfRecordsToPost.length; i++){       
          var postSuccessCallback = function(postRec) { 
              console.info('Posted ' + postRec);
          }($scope.ListOfRecordsToPost[i]);

          lsProductionService.post({}, postSuccessCallback); 
      }

暂无
暂无

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

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