116 votes

Quel est le moyen le plus propre d'obtenir la progression d'une requête JQuery ajax ?

En javascript, c'est très simple : il suffit d'attacher le callback à l'adresse suivante {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 quelle était la meilleure façon d'obtenir la progression d'une requête afin de l'afficher avec une petite barre de progression mais curieusement, je ne trouve rien d'utile dans la documentation de JQuery...

4 votes

Celui-ci semble prometteur dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5 pour html5

1 votes

Ooh merci les gars ! il faut donc remplacer xhr la chose étrange est que j'ai inspecté avec Chrome Dev Tools la soi-disant jqXHR (l'enveloppe de l'objet xhr retourné par $.ajax() ) et a trouvé un progress dans celui-ci (avec l'attribut abort , complete , success etc.), mais dans la documentation de JQuery, ce point est absent : api.jquery.com/jQuery.ajax/#jqXHR

3 votes

github.com/englercj/jquery-ajax-progress J'utilise ceci et c'est à peu près la même chose que les autres réponses mais je préfère avoir des choses plus génériques.

159voto

mattytommo Points 27587

Quelque chose comme ça pour $.ajax (HTML5 seulement cependant) :

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

1 votes

Cela semble prometteur, mais comment cela peut-il fonctionner ? L'ensemble du pipeline se compose de trois étapes : l'envoi d'une demande, le traitement de la demande dans le backend pour générer des données et le retour de celles-ci. Comment le côté client peut-il savoir ce qui est en train d'être fait dans le backend et combien de temps cela prendra-t-il pour calculer la progression ?

2 votes

L'en-tête de réponse HTTP nous indique le nombre d'octets à attendre, cette progression ne fait que compter le nombre d'octets reçus jusqu'à présent. Elle restera à zéro jusqu'à ce que la réponse HTTP soit effectivement envoyée.

2 votes

Est-ce que ça ne fonctionne que sur POST, et pas aussi sur GET et les autres ?

48voto

likerRr Points 590

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

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

Consultez le site github

0 votes

J'ai aimé la façon dont vous utilisez l'usine IFI. Je ne connaissais pas cette technique !

0 votes

C'est actuellement la meilleure solution proposée ici.

2 votes

Cette solution est efficace et élégante, mais vous devez savoir qu'elle risque de casser votre code existant, car elle supprime tous les appels aux fichiers dépréciés .success et .error. Elle supprime également tous les attributs non standard que vous définissez sur un objet jqXHR. Il ne fournit pas non plus le contexte dans "this" pour le callback uploadProgress (peut-être la même chose pour progress mais pas testé) comme il est fait pour toutes les promesses standard pour jqXHR. Vous devrez donc passer le contexte dans une fermeture.

6voto

MarkMYoung Points 28

J'ai essayé environ trois façons différentes d'intercepter la construction de l'objet Ajax :

  1. Ma première tentative a utilisé xhrFields mais cela ne permet qu'une seule écoute, ne s'attache qu'à la progression du téléchargement (et non de l'envoi), et nécessite ce qui semble être un copier-coller inutile.
  2. Ma deuxième tentative a attaché un progress à la promesse retournée, mais je devais maintenir mon propre tableau de gestionnaires. Je n'ai pas pu trouver un bon objet pour attacher les handlers parce qu'à un endroit j'avais accès au XHR et à un autre j'avais accès au XHR de jQuery, mais je n'avais jamais accès à l'objet différé (seulement sa promesse).
  3. Ma troisième tentative m'a permis d'accéder directement au XHR pour attacher des gestionnaires, mais elle nécessitait à nouveau trop de copier-coller de code.
  4. J'ai terminé ma troisième tentative et j'ai remplacé l'élément de jQuery ajax avec les miens. Le seul inconvénient potentiel est que vous ne pouvez plus utiliser votre propre xhr() réglage. Vous pouvez tenir compte de cette possibilité en vérifiant si options.xhr est une fonction.

En fait, j'appelle mon promise.progress fonction xhrProgress pour que je puisse le retrouver facilement plus tard. Vous pourriez lui donner un autre nom pour séparer vos auditeurs de téléchargement et de chargement. J'espère que cela aidera quelqu'un, même si le posteur original 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 )
    {
        xmlHttpReq.addEventListener( 'progress', function download_progress( evt )
        {
            //window.console.debug( "download_progress", evt );
            handler.apply( this, [evt]);
        }, false );
        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 );

0 votes

Je viens d'essayer de mettre en œuvre votre solution mais ce code est un peu trop pro pour que je le comprenne - comment dois-je l'utiliser ? J'ai copié-collé tout votre code avant mon document.ready et j'ai essayé de faire ce qui suit $.ajax({ ... }).progress(function(evl) { console.log(evl); }); mais rien ne se passe. Pouvez-vous m'aider ? :)

0 votes

Quelle version de jQuery utilisez-vous ?

0 votes

@FloSchild, s'il vous plaît, ne modifiez pas mon code juste pour vos propres préférences de formatage.

3voto

Kevin Pei Points 2476

JQuery dispose d'un AjaxSetup() qui vous permet d'enregistrer des gestionnaires d'ajax globaux tels que beforeSend et complete pour tous les appels ajax ainsi que de vous permettre d'accéder au xhr pour faire le progrès que vous recherchez

2 votes

Merci pour le lien. Pouvez-vous inclure un exemple dans votre réponse ?

0 votes

$.ajaxSetup({ xhr : function () { console.log('setup XHR...') ; } }) ;

8 votes

Et un exemple qui répond à la question ? J'ai bien peur de ne pas pouvoir voter en faveur d'une réponse qui m'oblige à faire beaucoup de manipulations et de lectures, surtout quand la page liée ne dit rien sur le progrès. Honnêtement, je suis sceptique à ce sujet, surtout compte tenu de l'avertissement sur cette page, qui dit "Note : Global callback functions should be set with their respective global Ajax event handler methods-". .ajaxStart() , .ajaxStop() , .ajaxComplete() , .ajaxError() , .ajaxSuccess() , .ajaxSend() -plutôt que dans l'objet d'options pour $.ajaxSetup() .' < api.jquery.com/jQuery.ajaxSetup/#entry-longdesc >

0voto

Sri Nair Points 21

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

Je cherchais une solution similaire et j'ai trouvé celle-ci en pleine utilisation.

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();
});

}

et votre serveur sort

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');

0 votes

Cela montre la progression d'un script PHP en cours d'exécution, et non d'un appel AJAX.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X