2014-07-16 7 views
6

Vorrei inviare richieste di post in loop. Se invio per esempio 2 richieste di seguito, solo l'ultima richiesta ha effettivamente effettuato la richiamata.Invio di richiesta di post in ciclo

Cosa sto facendo di sbagliato?

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

è possibile controllare la scheda della rete del browser, che viene inviata una sola richiesta? – harishr

+0

@ Mr-domanda per favore prenditi il ​​tuo tempo per rivedere le risposte e scegliere quello corretto – domokun

risposta

4

Utilizzare un closure. Lasciate che vi mostri un semplice esempio

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

Nel tuo caso ... avvolgere la chiamata/funzione asincrona con una chiusura

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) 

} 

La sezione di seguito non è direttamente correlata alla domanda ma piuttosto ai commenti relativi a questa risposta.


L'esempio presentato il jsFiddle citato nei commenti e mostrato sotto è pieno di bug e come tale non prova niente.

È vero che questo frammento, anche se non si utilizza una chiusura, produce "Hello Kitty" tre volte; in realtà, se si sostituisce il metodo console.log() con uno alert() si vedrà che produce "Hello Kitty" sei, nove o anche dodici volte. Quindi, che diavolo sta succedendo?) Come è possibile ottenere la finestra di avviso spuntando sei, nove o dodici volte in un ciclo di tre iterazioni ?!

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

uscita:

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

Come si può vedere, abbiamo un errore e nove uscite 'Ciao Kitty' di fila :) prima che cambi la funzione di cui sopra vediamo due importanti cosa

First

onreadystatechange negozi di eventi una funzione o un riferimento da chiamare automaticamente ogni volta che la proprietà readyState cambia mentre la proprietà status mantiene lo stato dell'oggetto XMLHttpRequest.

readyState immobili valori possibili

  • 0: non richiesta inizializzate
  • 1: connessione server stabilita
  • 2: richiesta ricevuta
  • 3: elaborazione richiesta
  • 4: richiedere finito e risposta è pronto

status proprietà valori possibili

  • 200: OK
  • 404: Pagina non trovata

Seconda

Come ho detto nei commenti, jsfiddle.net non è affidabile per test di snippet asincroni senza alcune modifiche. In altre parole, il metodo GET deve essere modificato in POST e la proprietà url deve essere modificato a questo link /echo/html/ (per ulteriori opzioni di dare un'occhiata a jsFiddle documentation)

Ora, cambiamo l'esempio di cui sopra (e seguire i commenti all'interno del codice)

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

prima uscita: // sei uscite

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

2a uscita: // sei uscite

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

Senza le modifiche apportate nell'esempio (b), abbiamo due uscite diverse. Come puoi vedere, diversi output per diversi valori di proprietà readyState sono stati resi. Ma il valore di i è rimasto invariato.

3a uscita: // dopo decommentando le linee per la 3a uscita showned sopra nell'esempio (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 

Così, dopo uncommenting la funzione che tiene i come argomento, vediamo che il valore di i è stato salvato. Ma questo è ancora errato poiché ci sono sei uscite e ne abbiamo bisogno solo tre. Come non abbiamo bisogno di tutti i valori della readyState o status proprietà dell'oggetto XMLHttpRequest, cerchiamo di rimuovere il commento le due righe necessarie per la quarta uscita

4 ° uscita: // dopo decommentando le linee per l'uscita 4 ° showned sopra nella esempio (b) - infine tre uscite

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

Infine, questo dovrebbe essere la versione corretta del frammento e questo è ciò che dobbiamo.

Un altro meccanismo onnipotente onnipotente (come ho detto in precedenza) sarebbe la funzione bind() che non preferisco poiché è più lenta di una chiusura.

+0

hex494D49, probabilmente hai ragione ma dubito che OP sia particolarmente illuminato da questa risposta. Sig. Domanda, il problema è (pensiamo) che la parte '// DOING SOMETHING' che non ci hai detto contiene la variabile' i'. Ma è in una funzione di callback, che non funziona fino a quando non è terminato il ciclo 'for'; per allora 'i == this.selectedAvailableUnits.length', indipendentemente dal suo valore originale. In questa chiusura c'è una nuova variabile chiamata 'i', che in realtà è separata dall'originale' i'; è dichiarato solo all'interno della funzione, quindi il suo valore non viene reimpostato durante l'iterazione attraverso il ciclo. –

+0

@David Knipe Prendi il 'i' off e prova a echo tre volte di seguito' echo "Hello Kitty" 'senza chiusura :) L'' i' non è importante in questo caso. – hex494D49

+0

Ripensandoci, non penso che ci capiamo. Stai dicendo che l'ultimo esempio con '" Hello Kitty "' non funzionerebbe se la funzione fosse stata sostituita con un semplice blocco di codice? Non sono d'accordo. Perchè pensi questo? Hai un jsfiddle per dimostrarlo? –

2

dispiace, io non lavoro con angularjs, ma questi due metodi che post utilizzando jQuery o anche il lavoro di base XMLHttpRequest bene per me:

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

codice 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

Si sta tentando di utilizzare una variabile variabile, url, all'interno di un for-loop.

Se non si utilizza una chiusura all'interno di un ciclo, solo l'ultimo valore del proprio for verrà inoltrato alla chiamata $http.post.
Le chiusure all'interno di anelli possono essere una bestia difficile. Vedi questa domanda JavaScript closure inside loops – simple practical example e google per più teoria/dettagli.

Il codice dovrà essere regolato in qualcosa di simile:

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: riferimento aggiuntivo
Ho avuto un problema molto simile non molto tempo fa, e si può leggere su di esso qui: Angular JS - $q.all() tracking individual upload progress

1

È chiaramente un problema di chiusura. Ulteriori informazioni here

Inoltre, è consigliabile utilizzare risorse $ su $ http. (Ng-risorse).

Controlla l'esempio da inserire in ciclo utilizzando la risorsa.

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

      lsProductionService.post({}, postSuccessCallback); 
     }