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

IT技术 javascript ajax jquery xmlhttprequest
2021-02-07 07:45:42

在普通的 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 文档中找到任何有用的东西......

6个回答

像这样的东西$.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
    }
});
它是否仅适用于 POST,而不适用于 GET 和其他?
2021-03-26 07:45:42
看起来很有希望,但这怎么可能奏效呢?整个管道由三个步骤组成 - 发送请求,在后端处理请求以生成一些数据,并将其返回。客户端怎么可能知道后端正在做什么以及计算进度需要多长时间?
2021-03-27 07:45:42
HTTP 响应头告诉我们期望多少字节,这个进度只是计算到目前为止已经接收了多少字节。它将保持为零,直到实际发送 HTTP 响应
2021-04-02 07:45:42

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

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

github上查看

这是目前此处建议的最佳解决方案。
2021-03-19 07:45:42
有效且优雅的解决方案,但您可能知道它可能会破坏您现有的代码,因为它会破坏对已弃用的 .success 和 .error 的所有调用。它还删除您在 jqXHR 对象上设置的所有非标准属性。它也没有为uploadProgress回调(可能与进度相同但未测试)提供上下文到“this”,因为它是为jqXHR的所有标准Promise完成的。所以你需要在闭包中传递上下文。
2021-03-19 07:45:42
我收到错误:TypeError: $.ajax(...).progress(...).progressUpload is not a function.... 有什么问题?
2021-03-24 07:45:42
@UniversalGrasp 嗨,请在 github 上打开一个问题并提供有关您所做工作的信息。这个库已经很久没有更新了 :) 可能是 jQuery 本身发生了一些变化
2021-04-08 07:45:42
我喜欢你使用 IFI 工厂的方式。我不知道那个技术!
2021-04-09 07:45:42

我尝试了三种不同的拦截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 );
您使用的是哪个版本的 jQuery?
2021-03-14 07:45:42
@FloSchild,请不要仅仅为了您自己的格式偏好而编辑我的代码。
2021-03-22 07:45:42
所以我只是尝试实施您的解决方案,但这段代码有点太专业了,我无法理解 - 我该如何使用它?我在我的 document.ready 之前复制粘贴了你的整个代码并尝试做$.ajax({ ... }).progress(function(evl) { console.log(evl); });但没有发生任何事情。你能帮助我吗?:)
2021-04-10 07:45:42

jQuery 有一个AjaxSetup()函数,它允许您注册全局 ajax 处理程序,例如beforeSendcomplete为所有 ajax 调用以及允许您访问xhr对象以执行您正在寻找的进度

来自文档为未来的 Ajax 请求设置默认值。不推荐使用它。
2021-03-24 07:45:42
以及回答问题的示例?恐怕我不能赞成一个让我做很多摆弄和阅读的答案,尤其是当链接页面没有说明进展时。老实说,我对此持怀疑态度,尤其是考虑到该页面上的警告,上面写着“注意:全局回调函数应该使用它们各自的全局 Ajax 事件处理程序方法—— .ajaxStart(), .ajaxStop(), .ajaxComplete(), .ajaxError(), .ajaxSuccess(), ——.ajaxSend()而不是在选项对象中设置$.ajaxSetup().' < api.jquery.com/jQuery.ajaxSetup/#entry-longdesc >
2021-03-30 07:45:42
谢谢你的链接。你能在你的答案中包含一个例子吗?
2021-04-09 07:45:42
$.ajaxSetup({ xhr: function () { console.log('setup XHR...'); } });
2021-04-10 07:45:42

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 调用的进度。
2021-04-05 07:45:42