2014-07-16 21 views
6

Tôi muốn gửi yêu cầu đăng trong vòng lặp. Nếu tôi gửi cho ví dụ 2 yêu cầu liên tiếp chỉ yêu cầu cuối cùng thực sự thực hiện cuộc gọi lại.Gửi yêu cầu đăng trong vòng lặp

Tôi làm gì sai?

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); 
      });   
     } 
    }; 
+4

bạn có thể kiểm tra trong tab mạng trình duyệt, chỉ thực sự một yêu cầu được gửi không ?? – harishr

+0

@ mr-câu hỏi xin vui lòng dành thời gian của bạn để xem xét các câu trả lời và chọn đúng – domokun

Trả lời

4

Sử dụng closure. Hãy để tôi chỉ cho bạn một ví dụ đơn giản

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

Trong trường hợp của bạn ... quấn cuộc gọi không đồng bộ/chức năng với một đóng

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) 

} 

Phần dưới đây không liên quan trực tiếp đến câu hỏi mà đúng hơn là các nhận xét liên quan đến câu trả lời này.


Ví dụ nộp jsFiddle đề cập trong các ý kiến ​​và trình bày dưới đây là lỗi và như vậy nó không chứng minh bất cứ điều gì.

Đúng là đoạn mã này, thậm chí không sử dụng đóng cửa, mang lại 'Hello Kitty' ba lần; trên thực tế, nếu bạn thay thế phương thức console.log() bằng một phương thức alert(), bạn sẽ thấy rằng nó mang lại 'Hello Kitty' sáu, chín hoặc thậm chí mười hai lần. Vì vậy, cái quái gì đang diễn ra;) làm thế nào có thể để cửa sổ cảnh báo bật lên sáu, chín hay mười hai lần trong vòng lặp ba lần lặp?

// 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"); 
}; 

Output:

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

Như bạn có thể thấy, chúng tôi đã có một lỗi và chín 'Hello Kitty' đầu ra liên tiếp :) Trước khi tôi thay đổi chức năng ở trên chúng ta hãy xem hai quan trọng điều

cửa hàng kiện

onreadystatechange Đầu tiên một hàm hoặc tham chiếu được gọi tự động mỗi lần thay đổi thuộc tính readyState trong khi thuộc tính status giữ trạng thái của đối tượng XMLHttpRequest.

readyState tài sản giá trị có thể

  • 0: Yêu cầu không được khởi tạo
  • 1: kết nối máy chủ thành lập
  • 2: yêu cầu nhận được
  • 3: thực hiện yêu cầu
  • 4: yêu cầu hoàn thành và phản ứng đã sẵn sàng

status tài sản giá trị có thể

  • 200: OK
  • 404: Không tìm thấy

Second

Như tôi đã nói trong các ý kiến, jsfiddle.net là không đáng tin cậy cho thử nghiệm các đoạn mã không đồng bộ mà không có một số thay đổi. Nói cách khác phương pháp GET nên được thay đổi để POSTurl tài sản phải được thay đổi để liên kết này /echo/html/ (để biết thêm tùy chọn hãy xem jsFiddle documentation)

Bây giờ, chúng ta hãy thay đổi ví dụ từ trên (và làm theo ý kiến trong mã)

// 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"); 
}; 

sản lượng 1: // sáu đầu ra

(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' 

đầu ra 2: // sáu đầu ra

(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' 

Không có bất kỳ thay đổi nào được thực hiện trong ví dụ (b), chúng tôi có hai kết quả đầu ra khác nhau. Như bạn có thể thấy, các kết quả đầu ra khác nhau cho các giá trị thuộc tính readyState khác nhau đã được tạo ra. Nhưng giá trị của i vẫn giữ nguyên.

3 đầu ra: // sau uncommenting các dòng cho đầu ra 3 showned trên trong ví dụ (b)

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 

Vì vậy, sau khi uncommenting các chức năng mà giữ i như một cuộc tranh cãi, chúng ta thấy rằng giá trị trong số i đã được lưu. Nhưng điều này vẫn không chính xác vì có sáu đầu ra và chúng ta chỉ cần ba. Như chúng ta đã không cần tất cả các giá trị của readyState hoặc status tài sản của đối tượng XMLHttpRequest, chúng ta hãy bỏ ghi chú hai dòng cần thiết cho đầu ra thứ tư

đầu ra 4: // sau uncommenting các dòng cho đầu ra 4rd showned trên trong ví dụ (b) - cuối cùng là ba kết quả đầu ra

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

Cuối cùng, đây là phiên bản đúng của đoạn mã và đây là những gì chúng tôi cần.

Một cơ chế toàn năng, toàn năng khác (như tôi đã nói trước đây) sẽ là hàm bind() mà tôi không thích vì nó chậm hơn so với đóng.

+0

hex494D49, có lẽ bạn đang đúng nhưng tôi nghi ngờ rằng OP đặc biệt khai sáng bởi câu trả lời này. Câu hỏi, vấn đề là (chúng tôi nghĩ) rằng phần '// DOING SOMETHING' mà bạn không cho chúng tôi biết về chứa biến' i'. Nhưng nó trong một hàm gọi lại, mà không chạy cho đến sau khi vòng lặp 'for' đã kết thúc; vào lúc đó 'i == this.selectedAvailableUnits.length', bất kể giá trị ban đầu của nó là gì. Trong phần đóng này, có một biến mới gọi là 'i', thực sự tách biệt với' i' ban đầu; nó chỉ được khai báo bên trong hàm, vì vậy giá trị của nó không được đặt lại trên lặp qua vòng lặp. –

+0

@David Knipe Lấy 'i' ra và cố gắng lặp lại ba lần trong một hàng' echo "Hello Kitty" 'mà không đóng cửa :)' i' không quan trọng trong trường hợp này. – hex494D49

+0

Vào những suy nghĩ thứ hai, tôi không nghĩ chúng ta hiểu nhau. Bạn đang nói rằng ví dụ cuối cùng với '" Hello Kitty "' sẽ không hoạt động nếu chức năng được thay thế bằng một khối mã thông thường? Tôi không đồng ý. Tại sao bạn nghĩ rằng điều này? Bạn có một jsfiddle để chứng minh nó? –

2

Xin lỗi, tôi không làm việc với angularjs, nhưng hai phương pháp mà bài đăng bằng jQuery hoặc thậm chí công việc XMLHttpRequest cơ sở tốt cho tôi:

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

đang Server (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); 
}); 
1

Bạn đang cố gắng sử dụng biến số thay đổi, url, bên trong một số for-loop.

Nếu bạn không sử dụng đóng cửa bên trong vòng lặp, chỉ giá trị cuối cùng của số for của bạn mới được chuyển đến cuộc gọi $http.post.
Đóng cửa bên trong vòng lặp có thể là một con thú khôn lanh. Xem câu hỏi này JavaScript closure inside loops – simple practical example và google để biết thêm lý thuyết/chi tiết.

Mã của bạn sẽ phải được điều chỉnh trong một cái gì đó như thế này:

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

Edit: thêm tài liệu tham khảo
Tôi đã có một vấn đề rất tương tự cách đây không lâu, và bạn có thể đọc về nó ở đây: Angular JS - $q.all() tracking individual upload progress

1

Sự cố đóng cửa rõ ràng của nó. Đọc thêm here

Ngoài ra, đề xuất sử dụng $ tài nguyên trên $ http. (ng-tài nguyên).

Xem ví dụ để đăng trong vòng lặp bằng tài nguyên.

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

      lsProductionService.post({}, postSuccessCallback); 
     } 
Các vấn đề liên quan