Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

IE8实现Ajax方式加载的进度条

  在现代浏览器上要让请求显示进度条非常简单,只要通过XHR对象的progress方法就可以实现。但是IE8是一个过渡产物,它对现代浏览器的特性支持的还不完全,所以需要非常麻烦地实现这个功能。这里通过XDR和XHR两个对象协作来完成进度条的功能。
  实际上IE8所支持的XDomainRequest对象(XDR对象)是支持progress事件的,但它的事件参数不好用。现代浏览器可以直接从progress的事件参数中获取数据的总字节数和已加载的字节数,而IE8没有这个支持。现在我们要解决的问题就是获取数据的总字节数和已加载的字节数。
  首先是总字节数的问题。在HTTP上,客户端想获取数据的总字节数,唯一的办法就是通过响应头里的Content-Length字段。但是XDR对象不支持getResponseHeader方法。于是我们只能靠XHR对象来获取,但我们并不需要资源的内容,只要资源的头,因此发起请求的HTTP方法使用HEAD就可以了。
  得到了总字节数之后,要考虑如何得到已加载的字节数。XDR对象可以在数据加载过程中通过responseText属性访问已经加载的数据。但仅此而已,这个属性访问到的只是文本数据。我们还需要做的是统计这些文本数据的字节数,这需要根据编码来计算。
  解决了这两个问题之后,IE8实现加载的进度条就没什么障碍了,下面是一段基于PHP的测试代码。
<?
/*
注意:
 1. 请关闭GZIP后测试
 2. PHP需要默认开启 output buffer
 3. 以下测试代码仅支持IE8
*/
ob_clean(); //清除BOM
?>
<script>
(function(url,callback){
  var xhr=new XMLHttpRequest;
  //只请求资源头,因为我们的目的是获取Content-Length这个字段
  xhr.open("HEAD",url,true);
  xhr.send();
  xhr.onreadystatechange=function(){
    if(xhr.readyState<4)return;
    callback(url,xhr.getResponseHeader("Content-Length")*1);
  };
})("test.php?ajax",function(url,total){
  var xdr=new XDomainRequest;
  xdr.open("GET",url,true);
  xdr.send();
  xdr.onload=function(){
    console.log("加载完成");
  };
  xdr.onprogress=function(){
    var loaded=getLoadedLength();
    console.log(
      (loaded/total*100).toFixed(2)+"% ("+
      loaded+"/"+total+")"
    );
  };
  function getLoadedLength(){
    //按UTF-8编码计算字节数(不考虑4字节UTF-8,因为IE8不支持)
    return xdr.responseText
      .replace(/[\u0080-\u07FF]/g,"00")
      .replace(/[\u0800-\uFFFF]/g,"000")
      .length;
  };
});
</script>
<?
//为了测试方便,只对程序发起的请求执行下面的程序
if(isset($_GET['ajax'])){
  $size=1E4; //我们将会创建1E4字节的额外数据
  //XDR对象所需的访问许可
  header('Access-Control-Allow-Origin: http://127.0.0.1');
  //最后手动设置Content-Length,因为PHP上数据超过8000字节时无法自动计算
  header('Content-Length: '.($size+ob_get_length()));
  //设置文档类型和编码类型
  header('Content-Type: text/html; charset=utf-8');
  //输出缓冲区内的数据
  ob_end_flush();
  //将数据分成10份,分散在1秒内传输
  $count=10;
  for($i=0;$i<$count;$i++){
    echo str_repeat(' ',$size/$count);
    usleep(1000/$count*1000);
    flush();
  };
};
?>
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^