什么是获得JQuery ajax请求进度的最干净的方法?


104

用简单的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
这个看起来很有希望的dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5 for html5
PSL

1
哦,谢谢大家!所以需要覆盖XHR ..奇怪的是,我已经与Chrome浏览器开发工具检查所谓的jqXHR对象(通过返回XHR对象的包装$.ajax()),发现progress在它的属性(沿abortcompletesuccess,等),但在JQuery文档中缺少此内容:api.jquery.com/jQuery.ajax/#jqXHR
guari

3
github.com/englercj/jquery-ajax-progress我使用它,它和其他答案完全一样,但是我更
喜欢

Answers:


139

这样的东西$.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
    }
});

1
看起来很有希望,但是这怎么可能呢?整个管道包括三个步骤-发送请求,在后端处理该请求以生成一些数据,然后将其返回。客户端如何才能知道后端正在做什么以及需要多少时间才能计算进度?
SexyBeast

1
HTTP响应标头告诉我们期望有多少个字节,此进度仅是计算到目前为止已收到的字节数。它将保持为零,直到实际发送HTTP响应
J. Allen

2
它只能在POST上运行,不能同时在GET和其他程序上运行吗?
拉兹

43

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

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

github上查看


我喜欢您使用IFI工厂的方式。我不知道该技术!
CodeArtist

这是目前建议的最佳解决方案。
2015年

2
可行且优雅的解决方案,但您可能会意识到它会破坏您现有的代码,因为它会破坏对已弃用的.success和.error的所有调用。它还会剥离您在jqXHR对象上设置的所有非标准属性。它也没有像针对jqXHR的所有标准promise一样为uploadProgress回调提供“ this”的上下文(对于进度可能是相同的,但未经测试)。因此,您将需要在闭包中传递上下文。
2016年

4
我收到错误消息:TypeError: $.ajax(...).progress(...).progressUpload is not a function....这是什么问题?
Universal Grasp

@UniversalGrasp嗨,请在github上打开一个问题,并提供有关您所做工作的信息。这个库没有更新很
长时间了

5

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

  1. 我的第一次尝试使用xhrFields,但是仅允许一个侦听器,仅附加下载(而不是上传)进度,并且需要看起来不必要的复制和粘贴。
  2. 我的第二次尝试将progress函数附加到返回的Promise,但是我必须维护自己的处理程序数组。我找不到合适的对象来附加处理程序,因为我可以访问XHR的另一个地方,可以访问jQuery XHR的地方,但是我从来没有访问延迟的对象(只有它的Promise)。
  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 );

因此,我只是尝试实现您的解决方案,但是对于我来说,这段代码有点过于专业了-我该如何使用它?我将粘贴的整个代码复制到document.ready之前,并尝试进行操作,$.ajax({ ... }).progress(function(evl) { console.log(evl); });但是没有任何反应。你能帮助我吗?:)
Patrick DaVader

您正在使用哪个版本的jQuery?
Flo Schild

@FloSchild,请勿仅出于您自己的格式设置偏好而编辑我的代码。
MarkMYoung

3

jQuery具有AjaxSetup()允许您注册全局ajax处理程序(例如beforeSendcomplete针对所有ajax调用)的功能,并允许您访问xhr对象以执行所需的进度


2
感谢您的链接。您可以在答案中加入一个例子吗?
Michael Scheper,2015年

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

7
还有一个回答问题的例子?恐怕我无法接受让我做很多事情的问题,尤其是当链接的页面没有任何进展时。老实说,我对此持怀疑态度,尤其是考虑到页面上的警告,上面写着“注意:全局回调函数应该用各自的全局AJAX事件处理方法-设置.ajaxStart().ajaxStop().ajaxComplete().ajaxError().ajaxSuccess().ajaxSend()比选项中-rather对象; $.ajaxSetup()。” < api.jquery.com/jQuery.ajaxSetup/#entry-longdesc >
Michael Scheper

1
从docs为将来的Ajax请求设置默认值。不建议使用它。
Oyvind

-1

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

这显示了正在运行的PHP脚本而不是AJAX调用的进度。
Sinus Mackowaty

-3

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

  1. 使用HTML和CSS创建Spinner或使用Bootstrap Spinner。
  2. 当最终用户请求AJAX数据进行无限循环或阈值限制时间时,显示Spinner。
  3. 因此,在AJAX请求的成功/错误结果之后,删除当前显示的微调框并显示结果。

为简单起见,我建议您使用JS类来为此目的动态显示和隐藏微调框。

我希望这有帮助!


2
那根本不是“获得进度”,而只是显示“等待”动画。
Sinus Mackowaty
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.