115

在普通的 javascript 中非常简单:只需要​​将回调附加到{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);

但我正在做一个 ajax 网站,它使用 JQuery($.get()$.ajax())下载 html 数据,我想知道哪个是获取请求进度的最佳方法,以便用一点进度条显示它,但奇怪的是,我不是在 JQuery 文档中找到任何有用的东西......

4

6 回答 6

156

像这样的东西$.ajax(虽然只有 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
    }
});
于 2013-10-01T22:27:08.750 回答
47

jQuery 已经实现了 Promise,所以最好使用这种技术,不要将事件逻辑移动到options参数中。我制作了一个添加进度承诺的 jQuery 插件,现在它就像其他承诺一样易于使用:

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

在github 上查看

于 2015-08-28T13:50:23.707 回答
5

我尝试了三种不同的方式来拦截 Ajax 对象的构造:

  1. 我的第一次尝试使用xhrFields了,但这只允许一个听众,只附加下载(而不是上传)进度,并且需要看似不必要的复制和粘贴。
  2. 我的第二次尝试将一个函数附加progress到返回的 Promise 上,但我必须维护自己的处理程序数组。我找不到一个好的对象来附加处理程序,因为一个地方我可以访问 XHR,另一个地方我可以访问 jQuery XHR,但我从来没有访问过延迟对象(只有它的承诺)。
  3. 我的第三次尝试让我可以直接访问 XHR 以附加处理程序,但再次需要大量复制和粘贴代码。
  4. 我结束了我的第三次尝试并ajax用我自己的替换了 jQuery。唯一的潜在缺点是您不能再使用自己的xhr()设置。您可以通过检查是否options.xhr是函数来允许这样做。

我实际上调用了我的promise.progress函数xhrProgress,以便以后可以轻松找到它。您可能希望将其命名为其他名称以分隔您的上传和下载侦听器。我希望这对某人有所帮助,即使原始海报已经得到了他需要的东西。

(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 );
于 2014-02-03T17:58:52.740 回答
3

jQuery 有一个功能,允许您注册全局 ajax 处理程序,AjaxSetup()例如所有 ajax 调用,并允许您访问对象以执行您正在寻找的进度beforeSendcompletexhr

于 2013-10-01T22:26:10.473 回答
0

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

我正在寻找类似的解决方案,发现这个使用已满。

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

}

和你的服务器输出

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');
于 2015-08-16T08:12:07.480 回答
-4

按照以下步骤显示 Ajax 请求的进度:

  1. 使用 Html & CSS 或使用 Bootstrap Spinner 创建一个 Spinner。
  2. 当最终用户请求 AJAX 数据以进行无限循环或阈值限制时间时,显示 Spinner。
  3. 因此,在 AJAX 请求的 SUCCESS / ERROR 结果之后,删除当前显示的 Spinner 并显示您的结果。

为方便起见,我建议您为此目的使用 JS 类动态显示和隐藏微调器。

我希望这有帮助!

于 2019-09-26T16:51:09.283 回答