Javascript 在for循环中发送post请求

Javascript 在for循环中发送post请求,javascript,angularjs,for-loop,http-post,Javascript,Angularjs,For Loop,Http Post,我想在循环中发送post请求。 例如,如果我一行发送2个请求,那么只有最后一个请求真正进行了回调 我做错了什么 this.assignAUnits = function(){ var currentIncidentId = this.incident.incidentId; for (var i=0; i< this.selectedAvailableUnits.length; i++){ var unit = this.select

我想在循环中发送post请求。 例如,如果我一行发送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);
            });          
        }
    };
this.assignAUnits=function(){
var currentIncidentId=this.incidentId.incidentId;
对于(var i=0;i
使用一个
闭包
。让我给你看一个简单的例子

// 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"];
?>
输出:

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:请求已完成,响应已准备就绪
状态
属性可能值

  • 200:好的
  • 404:找不到页面

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

现在,让我们更改上面的示例(并遵循代码中的注释)

第二项产出:/六项产出

(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
的值保持不变

第三个输出://在取消注释示例(b)中上述第三个输出的行之后

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

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

i=0 - readyState=4 - Hello Kitty
i=1 - readyState=4 - Hello Kitty
i=2 - readyState=4 - Hello Kitty 
最后,这应该是代码段的正确版本,这就是我们需要的


另一个万能的、万能的机制(正如我之前形象地说的)是
bind()
函数,我不喜欢它,因为它比闭包慢。

对不起,我不使用angularjs,但是使用jQuery甚至base 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>

您试图在
for循环
中使用一个不断变化的变量
url

如果在循环中不使用闭包,则只有
for
的最后一个值将进入
$http.post
调用。
循环中的闭包可能是一个棘手的问题。查看此问题,并通过谷歌搜索了解更多理论/细节

您的代码必须按如下方式进行调整:

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)
        }
    };
var doPost=函数(url){
$http.post(url)。然后(
功能(响应){
//做某事
},
函数(错误){
警报(错误);
});
}
this.assignAUnits=函数(){
var currentIncidentId=this.incidentId.incidentId;
对于(var i=0;i
编辑:附加参考

不久前,我遇到了一个非常类似的问题,您可以在这里阅读:

这显然是一个结束问题。 阅读更多

还建议使用$resource而不是$http。(ng资源)

查看使用资源为循环post的示例

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

          lsProductionService.post({}, postSuccessCallback); 
      }

对于(var i=0;我可以在浏览器网络选项卡中检查,是否真的只发送了一个请求???@mr问题请花时间查看答案并选择正确的答案Hex4949,您可能是对的,但我怀疑OP是否特别受此答案启发。问题先生,问题是(我们认为)您没有告诉我们的
//DOING SOMETHING
部分包含变量
i
。但它位于回调函数中,直到
for
循环完成后才会运行;到那时
i==this.selectedAvailableUnits.length
,而不管其原始值如何。在这个闭包中有一个新变量called
i
,它实际上是与原始的
i
分开的;它只在函数中声明,因此它的值不会在循环的迭代中重置。@David Knipe关闭
i
并尝试连续三次回显
回显“Hello Kitty”
,而不关闭:)在这种情况下,
i
并不重要。仔细想想,我认为我们彼此不了解。你是说,如果函数被替换为一个普通的代码块,那么最后一个例子“Hello Kitty”
就不起作用了?我不同意。你为什么这么想?你有JSFIDLE来演示吗?@DavidKnipe好吧,这是你的r
i=0 - readyState=4 - Hello Kitty
i=1 - readyState=4 - Hello Kitty
i=2 - readyState=4 - Hello Kitty 
<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>
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);
});
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)
        }
    };
      for(var i=0; i<$scope.ListOfRecordsToPost.length; i++){       
          var postSuccessCallback = function(postRec) { 
              console.info('Posted ' + postRec);
          }($scope.ListOfRecordsToPost[i]);

          lsProductionService.post({}, postSuccessCallback); 
      }