javascript使用ajax下载文件进度条实现

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<title></title>
</head>
<body>
<div id="a1" data-filename="2018.rar">下载</div>
<div id="progressing"></div>
<script>$('#a1').click(function () {var that = this;var page_url = 'http://localhost/test.php';var req = new XMLHttpRequest();req.open("get", page_url, true);//监听进度事件req.addEventListener("progress", function (evt) {if (evt.lengthComputable) {var percentComplete = evt.loaded / evt.total;console.log(percentComplete);$("#progressing").html((percentComplete * 100) + "%");}}, false);req.responseType = "blob";req.onreadystatechange = function () {if (req.readyState === 4 && req.status === 200) {var filename = $(that).data('filename');if (typeof window.chrome !== 'undefined') {// Chrome versionvar link = document.createElement('a');link.href = window.URL.createObjectURL(req.response);link.download = filename;link.click();} else if (typeof window.navigator.msSaveBlob !== 'undefined') {// IE versionvar blob = new Blob([req.response], { type: 'application/force-download' });window.navigator.msSaveBlob(blob, filename);} else {// Firefox versionvar file = new File([req.response], filename, { type: 'application/force-download' });window.open(URL.createObjectURL(file));}}};req.send();});
</script>
</body>
</html>

XHR实例的创建

为了实现兼容IE5、IE6浏览器版本,所以可以用下面的代码创建XHR实例。

var xhr;
if (window.XMLHttpRequest)
{//  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码xhr=new XMLHttpRequest();
}
else
{// IE6, IE5 浏览器执行代码xhr=new ActiveXObject("Microsoft.XMLHTTP");
}

XHR请求
XHR可以通过HTTP协议与服务器交换数据,要发送HTTP请求要使用到下面这些方法和属性:

open方法

open方法用于创建HTTP请求,但是请求并未发送,其定义如下:

open(method, url [, async = true [, username = null [, password = null]]])

  1. 参数method定义请求的类型,如GET、POST方法等等,大小写不敏感
  2. 参数url定义请求的URL地址
  3. 参数async定义是否异步处理请求,true(异步)或者false(同步),默认为true
  4. 参数username定义用户名,不常用,默认为null
  5. 参数password定义密码,不常用,默认为null

setRequestHeader方法

setRequestHeader方法用于向请求添加HTTP头,其定义如下:

setRequestHeader(name, value)

  1. 参数name定义HTTP请求头部的名称参数value定义HTTP请求头部的值
注意:
  • setRequestHeader方法必须在open方法调用之后、send方法之前调用,否则会出现异常
  • setRequestHeader方法可以连续调用多次,如果已经存在同名的HTTP头时,最终结果是追加而不是覆盖

client.setRequestHeader(‘X-Test’, ‘one’);
client.setRequestHeader(‘X-Test’, ‘two’);

timeout属性

timeout属性用于设置HTTP请求的超时时间,单位毫秒。当发生超时时,会触发ontimeout事件。在IE中,超时属性只能在调用 open() 方法之后且在调用 send() 方法之前设置。

upload属性

upload用于在数据传输到服务器时收集一些传输信息,比如上传了多少字节,总共多少字节等,其里面还包含了一些事件回调。

send方法

send方法用于发送open方法创建的HTTP请求,其定义如下:

send([body = null])
参数body定义HTTP请求的数据,当HTTP请求的方法为GET、HEAD时,该参数被忽略。body的类型可以为ArrayBuffer(二进制缓冲数组)、Blob(二进制大对象)、Document(类似XML格式的数据)、DOMString(字符串)、FormData(表单)。
上面几种数据类型的介绍可参考:

ArrayBuffer、Blob、Document、DOMString、FormData类型的数据介绍

abort方法

当请求发送后如果想终止这个请求,则可以调用abort方法,其定义如下:

abort()
XHR事件回调
当XHR发送异步请求后,我们无法知道请求是否发生了异常、请求何时到达服务器、服务器何时返回响应数据。XHR为我们提供了很多的事件回调,用来通知我们请求及响应状态的改变。下面的接口定义语言描述了跟XHR相关的事件接口定义。

interface XMLHttpRequestEventTarget : EventTarget {// event handlersattribute EventHandler onloadstart;attribute EventHandler onprogress;attribute EventHandler onabort;attribute EventHandler onerror;attribute EventHandler onload;attribute EventHandler ontimeout;attribute EventHandler onloadend;
};interface XMLHttpRequestUpload : XMLHttpRequestEventTarget {};interface XMLHttpRequest : XMLHttpRequestEventTarget {// event handlerattribute EventHandler onreadystatechange;// states//XHR的状态定义const unsigned short UNSENT = 0;const unsigned short OPENED = 1;const unsigned short HEADERS_RECEIVED = 2;const unsigned short LOADING = 3;const unsigned short DONE = 4;//用于描述XHR的状态readonly attribute unsigned short readyState;// request[SameObject] readonly attribute XMLHttpRequestUpload upload;
};

readyState属性用于描述XHR的状态,它有下面五种状态:
值 状态 描述

  • UNSENT 最初始状态,还未调用open方法
  • OPENED 已经调用了open方法
  • HEADERS_RECEIVED 已经调用了send方法,响应的HTTP头部和状态可以获取
  • LOADING 正在下载数据,下载的数据还不完整
  • DONE 数据下载完成
    onreadystatechange属性可以指定一个回调函数,当XHR的状态(即readyState)发生改变时就会调用该函数,可以在这个回调函数中判断请求是否成功。
   xhr.onreadystatechange = function() {if (xhr.readyState == 4) {//当XHR的状态为4时判断请求成功与否,然后处理响应的数据,虽然当XHR的状态为2或者3时可以获取到响应状态,但是此时的数据还未下载完全,不能处理响应数据if (xhr.status == 200) {//请求成功,处理响应数据} else {//请求失败}}}

upload属性代表上传数据的过程,它是XMLHttpRequestUpload的实例,XMLHttpRequestUpload继承XMLHttpRequestEventTarget接口,XMLHttpRequestEventTarget有7个回调方法,在数据上传的过程中会调用相应的方法。XHR也继承XMLHttpRequestEventTarget接口,因此它也拥有这些回调方法,但是它的回调方法大多都是从服务器下载响应数据的过程中触发的。
事件触发的时机
upload的回调方法会在数据上传的过程中触发,XHR的回调方法大多在响应数据下载的过程中触发,具体的触发时机见下表:

事件 触发时机

onreadystatechange 当readyState的值改变时触发,除了当它从非0变成0时
onloadstar t 当调用send方法时会触发xhr.onloadstart,然后会触发xhr.upload.onloadstart,代表开始上传数据
onprogress 上传数据过程中会触发xhr.upload.onprogress,下载数据过程中会触发xhr.onprogress,onprogress每50ms会触发一次
onabort 调用abort方法后会触发
onerror 当发生网络异常的时候会触发,如果上传数据的过程还未结束,此时会先触发xhr.upload.onerror,然后再触发xhr.onerror;如果上传数据的过程已经结束,此时只会触发xhr.onerror
onload 上传数据成功,会触发xhr.upload.onload;下载数据成功会触发xhr.onload
ontimeout 当服务端响应的时间超过指定的timeout时间时,会触发此事件
onloadend 上传数据完成(成功或者失败)时会触发xhr.upload.onloadend;下载数据完成(成功或失败)会触发xhr.onloadend

事件触发的顺序
通过下面的代码验证,可以得出事件触发的顺序。

 var xhr = new XMLHttpRequest();xhr.timeout = 1;//xhr eventsxhr.onreadystatechange = function() {console.log("onreadystatechange(),readyState=" + xhr.readyState);}xhr.onloadstart = function(event) {console.log("onloadstart()");}xhr.onprogress = function(event) {console.log("onprogress()");}xhr.onabort = function(event) {console.log("onabort()");}xhr.onerror = function(event) {console.log("onerror()");}xhr.onload = function(event) {console.log("onload()");}xhr.ontimeout = function(event) {console.log("ontimeout()");}xhr.onloadend = function(event) {console.log("onloadend()");}//upload eventsxhr.upload.onloadstart = function(event) {console.log("upload.onloadstart()");}xhr.upload.onprogress = function(event) {console.log("upload.onprogress()");}xhr.upload.onabort = function(event) {console.log("upload.onabort()");}xhr.upload.onerror = function(event) {console.log("upload.onerror()");}xhr.upload.onload = function(event) {console.log("upload.onload()");}xhr.upload.ontimeout = function(event) {console.log("upload.ontimeout()");}xhr.upload.onloadend = function(event) {console.log("upload.onloadend()");}try {xhr.open("POST", "http://localhost:8080/Server/test", true);xhr.send("hello");} catch (e) {alert(e.toString());}
打印的顺序如下://调用了open方法
onreadystatechange(),readyState=1
//调用了send方法
onloadstart()
//上传数据过程中的事件回调
upload.onloadstart()//开始上传请求数据
upload.onprogress()//正在上传请求数据
upload.onload()//成功上传请求数据
upload.onloadend()//完成上传请求数据
//下载响应数据过程中的事件回调
onreadystatechange(),readyState=2//已经获取到响应头部和响应状态码
onreadystatechange(),readyState=3//正在下载响应数据,改变状态
onprogress()//正在下载响应数据
onreadystatechange(),readyState=4//响应数据下载完成,改变状态
onload()//成功下载响应数据
onloadend()//完成下载响应数据

事件回调方法的参数
XMLHttpRequestEventTarget里面的回调方法的参数类型为ProgressEvent,ProgressEvent的定义如下:

interface ProgressEvent : Event {readonly attribute boolean lengthComputable;//数据长度是否可计算的readonly attribute unsigned long long loaded;//已经下载或者上传了多少字节readonly attribute unsigned long long total;//需要下载或者上传的总字节数
};

所以在onprogress方法回调中,可以通过loaded和total这两个属性来实现上传或者下载的进度条功能。

事件回调方法的添加方式
一种方式是直接为它指定函数的引用,如下方式:

    xhr.onloadstart = function(event) {console.log("onloadstart()");}

从上面的定义中可以看出,事件接口都继承自EventTarget,EventTarget的定义如下,其中有addEventListener方法,第一个参数时事件名称,没有“on”前缀,第二个参数时回调方法,其它参数为可选。

interface EventTarget {void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);boolean dispatchEvent(Event event);
};

因此下面的代码实现的效果与方式一相同

    xhr.addEventListener("loadstart", function(event) {console.log("loadstart()");});

XHR响应
了解了XHR的请求、XHR的事件回调之后,就剩下处理XHR响应的工作了,比如解析数据等等,要处理响应,需要了解下面的方法和属性。

  • getResponseHeader(ByteString name);参数name为HTTP响应头部的键值
  • getAllResponseHeaders方法可以获取所有的HTTP响应头的数据,其定义如下:
  • status和statusText属性status属性表示HTTP响应状态码,即200、404等;statusText属性表示HTTP响应状态的描述文本,即OK、Not Found等。

responseType、response、responseText、responseXML属性
可以在发送请求之前设置responseType,用于指定返回的响应数据的类型,responseType的类型有以下几种:

类型 描述

  • empty string 空字符串,这是默认值
  • arraybuffer 二进制缓冲数组
  • blob 二进制大对象
  • document 文档类型
  • json JSON类型
  • text 文本类型
    处理响应数据时,需要根据responseType来判断返回的数据类型。当responseType为text或者empty string类型时可以使用responseText属性,为其它类型时调用responseText会发生异常;当responseType为document或者empty responseXML属性,为其它类型时调用responseXML会发生异常;当responseType不是empty string、text、document类型时,需要转换成具体的类型进行解析。

处理响应数据的时机
方式一:

    xhr.onreadystatechange = function() {if (xhr.readyState === 4) {if (xhr.status === 200) {//处理数据} else {//其它操作}}}

方式二:

    xhr.onload = function(event) {if (xhr.status === 200) {//处理数据} else {//其它操作}}

通过XHR回调事件的触发时机我们可以知道,onreadystatechange回调会触发多次,因此方式二更优。

ajax实现下载文件进度条及方法详解相关推荐

  1. java spring mvc 上传_Java Spring MVC 上传下载文件配置及controller方法详解

    下载: 1.在spring-mvc中配置(用于100M以下的文件下载) 下载文件代码 @RequestMapping("/file/{name.rp}") public Respo ...

  2. java文件下载controller_Java Spring MVC 上传下载文件配置及controller方法详解

    下载: 1.在spring-mvc中配置(用于100M以下的文件下载) 下载文件代码 @RequestMapping("/file/{name.rp}") public Respo ...

  3. python gui下载进度条_对python GUI实现完美进度条的示例详解

    在用python做一个gui界面时,想搞一个进度条实时显示下载进度,但查阅很多博客,最后的显示效果都类似下面这种: 这种效果在cmd界面看着还可以,但放到图形界面时就有点丑了,所以我用canvas重新 ...

  4. python统计csv行数_对Python 多线程统计所有csv文件的行数方法详解

    如下所示: #统计某文件夹下的所有csv文件的行数(多线程) import threading import csv import os class MyThreadLine(threading.Th ...

  5. java解析日志数据_Java实时监控日志文件并输出的方法详解

    Java实时监控日志文件并输出的方法详解 想在前台显示数据同步过程中产生的日志文件,在网上找到解决方案,做了代码测试好用.这里做个记录 java.io.RandomAccessFile可以解决同时向文 ...

  6. python修改xml标签的值_对python修改xml文件的节点值方法详解

    这是我的xml文件结构 <?xml version='1.0' encoding='utf-8'?> JPEGImages train_2018-05-08_1000.jpg D:\all ...

  7. python对文件的处理_python文件处理fileinput使用方法详解

    这篇文章主要介绍了python文件处理fileinput使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.介绍 fileinput模块 ...

  8. 【文件md5值查看方法详解】:如何获取文件的唯一标识?

    [文件md5值查看方法详解]:如何获取文件的唯一标识? 在日常工作中,我们经常需要检查文件是否被篡改或者验证文件的完整性.而文件的MD5值就是一个很好的选择,因为它可以作为文件的唯一标识.那么,如何获 ...

  9. python fileinput_python文件处理fileinput使用方法详解

    这篇文章主要介绍了python文件处理fileinput使用方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.介绍 fileinput模块 ...

最新文章

  1. 记录一下g++的编译选项
  2. Asp.net2.0页面的生命周期(续)
  3. 3.列表(一个打了激素的数组)
  4. 【Spark Summit East 2017】BigDL:Spark上的分布式深度学习库
  5. 全局变量/static静态变量在section段中的分布
  6. 2016-1-29 图解HTTP(04)
  7. [Charset]UTF-8, UTF-16, UTF-16LE, UTF-16BE的区别
  8. 【NOIP2013模拟联考5】休息(rest)
  9. 更新系统时跳过某个软件包
  10. 均值差异大但是t检验不显著_T检验原理及介绍
  11. linux关闭gvim命令,Linux 下 8 种退出 vim 编辑器的方法
  12. linux sudo输入密码无法获得锁,Linux系统提示无法获得锁/var/lib/dpkg/lock怎么办?
  13. textview 复制粘贴_Android TextView使用剪贴板复制粘贴
  14. SpringBoot学习---Web开发(静态资源处理,首页和图标)
  15. CSS——div垂直居中及div内文字垂直居中
  16. Python代码加密-PyArmor
  17. 补血良方 核桃红枣阿胶糕
  18. [转载]W3C XML Schema 与文档类型定义
  19. 推荐4个好用、接收邮件及时的临时邮箱
  20. 数据运营-计算留存率和转化率(漏斗分析Python)

热门文章

  1. MTK6577+Android4.0背光点亮
  2. MyEclipse10 + Axis2 开发webservice
  3. 读取摩托罗拉数据在XPROG米V5.0没有响应和超时错误
  4. Excel对比两行数据是否相同?
  5. java对gzip格式进行压缩与解压缩
  6. 雷军:穿越人生低谷的感悟(节选)
  7. MYSEE:Sp数据结构分析初稿
  8. micropythonesp8266刷固件_MicroPython入坑记2:ESP8266/ESP32刷固件
  9. 如何在Windows使用 ffmpeg 转换整个目录?以MP4转MP3为例
  10. (B站动力节点老杜MySQL教程)MySQL课堂笔记-day03.txt