Qual è il modo più pulito per ottenere i progressi della richiesta Ajax di JQuery?

In plain javascript è molto semplice: basta attaccare il callback a {XMLHTTPRequest}.onprogress

 var xhr = new XMLHttpRequest(); xhr.onprogress = function(e){ if (e.lengthComputable) var percent = (e.loaded / e.total) * 100; }; xhr.open('GET', 'http://www...', true); xhr.onreadystatechange = function() { ... }; xhr.send(null); 

ma sto facendo un sito ajax che scarica i dati html con JQuery ( $.get() o $.ajax() ) e mi chiedevo quale sia il modo migliore per ottenere lo stato di avanzamento di una richiesta per visualizzarlo con un piccola barra di progresso ma curiosamente, non trovo nulla di utile nella documentazione di JQuery …

Qualcosa di simile a $.ajax (solo HTML5):

 $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); xhr.upload.addEventListener("progress", function(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; //Do something with upload progress here } }, false); xhr.addEventListener("progress", function(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; //Do something with download progress } }, false); return xhr; }, type: 'POST', url: "/", data: {}, success: function(data){ //Do something on success } }); 

jQuery ha già implementato delle promesse, quindi è meglio usare questa tecnologia e non spostare la logica degli eventi sul parametro delle options . Ho creato un plugin jQuery che aggiunge promesse di progresso e ora è facile da usare proprio come altre promesse:

 $.ajax(url) .progress(function(){ /* do some actions */ }) .progressUpload(function(){ /* do something on uploading */ }); 

Dai un’occhiata a github

jQuery ha una funzione AjaxSetup() che ti permette di registrare gestori globali di ajax come beforeSend e complete per tutte le chiamate ajax e ti permette di accedere all’object xhr per fare il progresso che stai cercando

Ho provato tre diversi modi di intercettare la costruzione dell’object Ajax:

  1. Il mio primo tentativo ha utilizzato xhrFields , ma consente solo un ascoltatore, si limita a scaricare (non caricare) i progressi e richiede ciò che sembra una copia e incolla inutile.
  2. Il mio secondo tentativo collegava una funzione di progress alla promise restituita, ma dovevo mantenere la mia propria schiera di gestori. Non sono riuscito a trovare un buon object per colbind i gestori perché in un posto avrei accesso all’XHR e un altro avrei accesso all’XHR di jQuery, ma non ho mai avuto accesso all’object posticipato (solo la sua promise).
  3. Il mio terzo tentativo mi ha dato l’accesso diretto all’XHR per il collegamento dei gestori, ma ancora una volta richiedevo molto codice di copia e incolla.
  4. Ho concluso il mio terzo tentativo e ho sostituito l’ ajax di jQuery con il mio. L’unica potenziale carenza è che non è più ansible usare la propria impostazione xhr() . Puoi permetterlo controllando per vedere se options.xhr è una funzione.

In realtà chiamo my xhrProgress function xhrProgress così posso trovarlo facilmente in seguito. Potresti voler nominarlo qualcos’altro per separare il tuo caricamento e scaricare i listener. Spero che questo aiuti qualcuno anche se il poster originale avesse già ciò di cui aveva bisogno.

 (function extend_jQuery_ajax_with_progress( window, jQuery, undefined ) { var $originalAjax = jQuery.ajax; jQuery.ajax = function (url, options) { if (typeof(url) === 'object') { options = url; url = undefined; } options = options || {}; // Instantiate our own. var xmlHttpReq = $.ajaxSettings.xhr(); // Make it use our own. options.xhr = function () { return(xmlHttpReq); }; var $newDeferred = $.Deferred(); var $oldPromise = $originalAjax(url, options) .done(function done_wrapper( response, text_status, jqXHR) { return($newDeferred.resolveWith(this, arguments)); }) .fail(function fail_wrapper(jqXHR, text_status, error) { return($newDeferred.rejectWith( this, arguments)); }) .progress(function progress_wrapper() { window.console.warn("Whoa, jQuery started actually using deferred progress to report Ajax progress!"); return($newDeferred.notifyWith( this, arguments)); }); var $newPromise = $newDeferred.promise(); // Extend our own. $newPromise.progress = function (handler) { // Download progress xmlHttpReq.addEventListener('progress', function download_progress(evt) { // window.console.debug( "download_progress", evt ); handler.apply(this, [evt]); }, false); // Upload progress xmlHttpReq.upload.addEventListener('progress', function upload_progress(evt) { // window.console.debug( "upload_progress", evt ); handler.apply(this, [evt]); }, false); return(this); }; return($newPromise); }; })(window, jQuery); 

http://www.htmlgoodies.com/beyond/php/show-progress-report-for-long-running-php-scripts.html

Stavo cercando una soluzione simile e ho trovato questo uso completo.

 var es; function startTask() { es = new EventSource('yourphpfile.php'); //a message is received es.addEventListener('message', function(e) { var result = JSON.parse( e.data ); console.log(result.message); if(e.lastEventId == 'CLOSE') { console.log('closed'); es.close(); var pBar = document.getElementById('progressor'); pBar.value = pBar.max; //max out the progress bar } else { console.log(response); //your progress bar action } }); es.addEventListener('error', function(e) { console.log('error'); es.close(); }); 

}

e le uscite del tuo server

 header('Content-Type: text/event-stream'); // recommended to prevent caching of event data. header('Cache-Control: no-cache'); function send_message($id, $message, $progress) { $d = array('message' => $message , 'progress' => $progress); //prepare json echo "id: $id" . PHP_EOL; echo "data: " . json_encode($d) . PHP_EOL; echo PHP_EOL; ob_flush(); flush(); } //LONG RUNNING TASK for($i = 1; $i <= 10; $i++) { send_message($i, 'on iteration ' . $i . ' of 10' , $i*10); sleep(1); } send_message('CLOSE', 'Process complete');