2013-04-05 13 views
6

Vorrei scrivere una funzione che esegue una dozzina di richieste asincrone asincrone, attendere che tutto finisca e quindi restituire informazioni aggregate. Come:Attendere la fine delle richieste Ajax asincrone

function countHealthy(urls) { 
    var healthy = 0; 
    for (var i = 0; i < urls.length; ++i) { 
    $.ajax({url: urls[i], async: true, id: i}) 
    .done(function (data) { ++healthy; }); 
    } 
    // Wait for all ajax to finish. 
    return healthy; 
} 

PS: è il filo ++ sano e sicuro?

risposta

6

Javascript non ha thread, quindi la sicurezza dei thread non è un problema. La tua dichiarazione di ritorno è il problema, è necessario andare nel callback che le chiamate ajax eseguono al completamento. Poiché ajax avviene in modo asincrono, come indica il codice, l'istruzione return viene attivata prima che tutte le richieste vengano restituite.

Si potrebbe voler verificare query deferreds, che sembra essere nato per questo tipo di cose. Direttamente da quel collegamento

function doAjax() { 
    return $.get('foo.htm'); 
} 

function doMoreAjax() { 
    return $.get('bar.htm'); 
} 

$.when(doAjax(), doMoreAjax()) 
    .done(function() { 
    console.log('I fire once BOTH ajax requests have completed!'); 
    }) 
    .fail(function() { 
    console.log('I fire if one or more requests failed.'); 
    }); 

Con un po 'di refactoring minore si potrebbe implementare questo in circa 2 minuti.

In alternativa, se si controlla il server, è possibile creare un endpoint del server che esegue tutto il controllo in una richiesta.

1

Si può fare questo:

var urls= ['url1', 'url2', 'url3', 'url4']; 
function doTheUrl() { 
    if (urls.length === 0) { 
     alert('All urls are done now.'); 
     return; 
    } 

    var url = urls.pop(); 
    $.ajax({ 
     url: "/DoTheJob", 
     complete: function() { 
      doTheUrl(); 
     } 
    }); 
}; 
+0

in realtà non credo che questo funzionerà. c'è un 'return' implicito alla fine della funzione. così quando la chiamata $ .ajax viene messa in pila, tutto continua a muoversi e la funzione termina. avrei downvote ora. – the0ther

0

Forse si può provare questo. Sto semplicemente eseguendo un ciclo while vuoto in modo che l'istruzione return non venga premuta finché non vengono restituite tutte le chiamate ajax.

function countHealthy(urls) { 
    var healthy = 0; 
    var urlCount = urls.length; 
    var numberOfAjaxCallsReturned = 0; 
    for (var i = 0; i < urls.length; ++i) { 
    $.ajax({url: urls[i], async: true, id: i}) 
     .done(function (data) { 
       ++healthy; 
       numberOfAjaxCallsReturned++; 
     }); 
    } 
    while(numberOfAjaxCallsReturned!=urlCount) 
    { 
    } 
    return healthy; 
} 
+1

prestazioni molto cattive su questo, non utile a mio parere. –

0

Se si dispone di una pagina complessa, si vuole tenere traccia e attendere specifical solo per il tuo chiamate asincrone per tornare. Questo perché potrebbero essere in esecuzione altre chiamate non cruciali.

Detto questo, per le pagine semplici è sufficiente controllare e attendere che non ci siano chiamate. Questo script jQuery controlla ogni trimestre per vedere se ci sono richieste asincrone correnti ogni quarto di secondo. Una volta che non ce ne sono, procederai.

var WaitForAjax = function() 
    { 
     if (jQuery.active == 0){ 
     } 
     else 
     { 
      setTimeout(WaitForAjax, 250); 
     } 
    } 

    function RunIt() 
    { 
     //IssueAjaxCalls would be where you make all your Ajax calls. 
     IssueAjaxCalls(); 

     WaitForAjax(); 

     //The KeepGoing function won't get called until there are no more Ajax calls pending. 
     KeepGoing(); 
    } 
0

Prima di tutto si sta facendo una richiesta AJAX su ogni ciclo che sembra un po 'di sprecare le risorse del server. Se questa funzione verrà chiamata molto, suggerirei di rifattorizzare il codice per fare meno query possibili.

In ogni modo, ecco come lo farei

function countHealthy(urls) { 

    var healthy = 0; 
    var reqs = []; 

    for (var i = 0; i < urls.length; ++i) { 
     reqs.push(
      $.ajax({ 
       url: urls[i], 
       id: i 
      }) 
     ); 
    } 
} 


$.when.apply($, reqs).then(function() { 
    // On success 
    ++healthy; 
}).fail(function() { 
    // When failed 
}).always(function() { 
    // this will be run no matter the outcome 
}); 

Non hanno avuto la possibilità di provarlo, quindi non sono sicuro se ho fatto un errore di sintassi, ecc modifiche per il tuo codice:

Rimosso async = true, ignoralo se prima lo avevi impostato da qualche parte nel codice.

Si può avere un'idea di come "when.apply" funziona, source

Problemi correlati