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

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

131193 次浏览

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

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

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

  1. 我的第一次尝试使用 xhrFields,但是它只允许一个监听器,只附加到下载(而不是上传)过程,并且需要看起来不必要的复制和粘贴。
  2. 我的第二次尝试将 progress函数附加到返回的承诺,但是我必须维护自己的处理程序数组。我无法找到一个好的对象来附加处理程序,因为一个地方我可以访问 XHR,另一个地方我可以访问 jQuery XHR,但是我从来没有访问过延迟对象(只有它的承诺)。
  3. My third attempt gave me direct access to the XHR for attaching handlers, but again required to much copy-and-paste code.
  4. 我完成了第三次尝试,并用自己的代码替换了 jQuery 的 ajax。唯一的潜在缺点是您不能再使用自己的 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 );

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

JQuery 已经实现了承诺,因此最好使用这种技术,而不要将事件逻辑移动到 options参数。我做了一个 jQuery 插件,增加了进度承诺,现在它很容易使用,就像其他承诺一样:

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

github看看

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

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

为了简单起见,我建议您使用 JS 类来动态显示和隐藏这个微调器。

I Hope this helps!