admin管理员组

文章数量:1134238

In plain javascript is very simple: need just to attach the callback to {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);

but I'm doing an ajax site that download html data with JQuery ($.get() or $.ajax()) and I was wondering which is the best way to get the progress of a request in order to display it with a little progress bar but curiously, I'm not finding anything usefull in JQuery documentation...

In plain javascript is very simple: need just to attach the callback to {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);

but I'm doing an ajax site that download html data with JQuery ($.get() or $.ajax()) and I was wondering which is the best way to get the progress of a request in order to display it with a little progress bar but curiously, I'm not finding anything usefull in JQuery documentation...

Share Improve this question asked Oct 1, 2013 at 22:21 guariguari 3,8103 gold badges29 silver badges26 bronze badges 3
  • 4 This one looks promising dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5 for html5 – PSL Commented Oct 1, 2013 at 22:27
  • 1 Ooh thanks guys! so need to override xhr.. the strange thing is that I've inspected with Chrome Dev Tools the so called jqXHR object (the wrapper of xhr object returned by $.ajax()) and found a progress attribute in it (along with abort, complete, success, etc.), but in JQuery docs this is missing: api.jquery.com/jQuery.ajax/#jqXHR – guari Commented Oct 2, 2013 at 9:14
  • 3 github.com/englercj/jquery-ajax-progress I use this and its quite the same as other answers but I prefere to have more generic stuff – KeizerBridge Commented Nov 5, 2014 at 14:59
Add a comment  | 

5 Answers 5

Reset to default 164

Something like this for $.ajax (HTML5 only though):

$.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 has already implemented promises, so it's better to use this technology and not move events logic to options parameter. I made a jQuery plugin that adds progress promise and now it's easy to use just as other promises:

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

Check it out at github

I tried about three different ways of intercepting the construction of the Ajax object:

  1. My first attempt used xhrFields, but that only allows for one listener, only attaches to download (not upload) progress, and requires what seems like unnecessary copy-and-paste.
  2. My second attempt attached a progress function to the returned promise, but I had to maintain my own array of handlers. I could not find a good object to attach the handlers because one place I'd access to the XHR and another I'd have access to the jQuery XHR, but I never had access to the deferred object (only its promise).
  3. My third attempt gave me direct access to the XHR for attaching handlers, but again required to much copy-and-paste code.
  4. I wrapped up my third attempt and replaced jQuery's ajax with my own. The only potential shortcoming is you can no longer use your own xhr() setting. You can allow for that by checking to see whether options.xhr is a function.

I actually call my promise.progress function xhrProgress so I can easily find it later. You might want to name it something else to separate your upload and download listeners. I hope this helps someone even if the original poster already got what he needed.

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

jQuery has an AjaxSetup() function that allows you to register global ajax handlers such as beforeSend and complete for all ajax calls as well as allow you to access the xhr object to do the progress that you are looking for

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

I was searching for a similar solution and found this one use full.

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

}

and your server outputs

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

本文标签: javascriptWhat is the cleanest way to get the progress of JQuery ajax requestStack Overflow