[英]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
屬性可能的值
status
屬性可能的值
第二
正如我在評論中所說,如果沒有一些更改,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
對象的readyState
或status
屬性的所有值,所以讓我們取消注釋第四個輸出所需的兩行
第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.