web-dev-qa-db-fra.com

Quel est le moyen le plus propre d’obtenir l’avancement de la requête JQuery ajax?

En clair, javascript est très simple: il suffit d’attacher le rappel à {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);

mais je fais un site ajax qui télécharge des données html avec JQuery ($.get() ou $.ajax()) et je me demandais quel est le meilleur moyen d’obtenir la progression d’une requête afin de l’afficher avec un message. petite barre de progression mais curieusement, je ne trouve rien d’utile dans la documentation JQuery ...

90
guari

Quelque chose comme ceci pour $.ajax (HTML5 seulement):

$.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
    }
});
130
mattytommo

jQuery a déjà mis en œuvre des promesses, il est donc préférable d'utiliser cette technologie et de ne pas déplacer la logique des événements vers le paramètre options. J'ai créé un plugin jQuery qui ajoute une promesse de progrès et est maintenant facile à utiliser, tout comme les autres promesses:

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

Vérifiez-le à github

37
likerRr

jQuery a une fonction AjaxSetup() qui vous permet d'enregistrer des gestionnaires d'ajax globaux tels que beforeSend et complete pour tous les appels ajax, ainsi que d'accéder à la xhr objet de faire le progrès que vous recherchez

5
Kevin Pei

J'ai essayé trois méthodes différentes pour intercepter la construction de l'objet Ajax:

  1. Ma première tentative utilisait xhrFields, mais cela ne permettait qu'à un seul auditeur, ne joignait que pour télécharger (pas télécharger) la progression, et nécessite ce qui semble être un copier-coller inutile.
  2. Ma deuxième tentative a associé une fonction progress à la promesse retournée, mais je devais gérer mon propre tableau de gestionnaires. Je ne pouvais pas trouver un bon objet pour attacher les gestionnaires car un endroit aurait accès au XHR et un autre au jQuery XHR, mais je n'ai jamais eu accès à l'objet différé (seulement sa promesse).
  3. Ma troisième tentative m'a donné un accès direct à XHR pour attacher des gestionnaires, mais encore une fois, il a fallu beaucoup de code copier-coller.
  4. J'ai terminé ma troisième tentative et remplacé le ajax de jQuery par le mien. Le seul inconvénient potentiel est que vous ne pouvez plus utiliser votre propre réglage xhr(). Vous pouvez le faire en vérifiant si options.xhr est une fonction.

J'appelle en fait ma fonction promise.progressxhrProgress afin de pouvoir la retrouver facilement plus tard. Vous voudrez peut-être lui attribuer un autre nom pour séparer votre téléchargement et télécharger les écouteurs. J'espère que cela aidera quelqu'un même si l'affiche originale a déjà obtenu ce dont il avait besoin.

(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);
4
MarkMYoung