AJAX

摘要

一、老版本的XMLHttpRequest对象
二、老版本的缺点
三、 新版本的功能介绍
四、HTTP请求的实现
五、FormData对象
六、上传文件
七、跨域请求(CORS)
八、接受二进制数据
九、进度信息
十、readyState和常见响应状态码
十一、AJAX的优点

XMLHttpRequest是一个浏览器接口,使得JavaScript可以进行HTTP(S)通信。

最早,微软在IE5引进了这个接口。因为它太有用,其他浏览器模仿部署了,AJAX(异步js和XML)操作因此得以诞生

但是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不同,HTML5的概念形成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案

这个XMLHttpRequest的新版本,提出了很多有用的新功能,将大大推动互联网革新。


一、老版本的XMLHttpRequest对象

在介绍新版本之前,我们先回顾一下老版本的用法
首先,新建一个XMLHttpRequest的实例

  var xhr = new XMLHttpRequest();

然后,向服务器发送一个HTTP请求。

xhr.open('GET', 'example.php');
xhr.send();

接着,就等待远程主机做出回应。这时需要监控XMLHttpRequest对象的状态变化,指定回调函数

xhr.onreadyStatechange = function(){
  if( xhr.readyState == 4 & xhr.status == 200){
        alert( xhr.responseText);
   }else{
         alert(xhr.statusText);
   }
}

上面的代码包含了老版本XMLHttpRequest对象的主要属性:

* xhr.readyState:XMLHttpRequest对象的状态,等于4表示数据已经接收完毕
* xhr.status: 服务器返回的状态码,等于200表示一切正常
* xhr.responseText: 服务器返回的文本数据
* xhr.repsonseXML: 服务器返回的XML格式的数据
* xhr.statusText: 服务器返回的状态文本

二、老版本的缺点

  • 只支持文本数据的传送,无法用来读取和上传二进制文件
  • 没有进度信息,传送和接受信息,只能提示有没有完成
  • 同域限制

三、 新版本的功能

  • 可以设置HTTP请求的时限
  • 可以使用FormData对象管理表单数据
  • 可以上传文件
  • 可以跨域请求
  • 可以获取服务端的二进制数据
  • 可以获得数据传输的进度信息

下面,我就一一介绍这些新功能

四、HTTP请求的实现

有时,ajax操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。

新版本的XMLHttpRequest对象,增加了timeout属性,可以设置HTTP请求的时限

xhr.timeout = 3000;

上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout时间,用来指定回调函数

xhr.ontimeout  = function(event){
  alert('请求超时!');
}

五、FormData对象

ajax操作往往用来传递表单数据。为了方便表单处理,HTML5新增了一个FormData对象,可以模拟表单
首先,新建一个FormData对象

var formData = new FormData();

然后,为它添加表单项

formData.append('username', '张三');
formData.append('id', 123456);

最后,直接传送这个FormData对象,这与提交网页表单的效果,完全一样

xhr.send(formdata)

FormData对象也可以用来获取网页表单的值。

var form = document.getElementById('myform');
var formData = new FormData(form);
formData.append('secret', '123456'); // 添加一个表单项
xhr.open('POST', form.action);
xhr.send(formData);

六、上传文件

新版XMLHttpRequest对象,不仅可以发送文本信息,还可以上传文件
假定files是一个“选择文件”的表单元素(input[type="fule"]),我们将它装入FormData对象

var formData = new FormData()
for (var i = 0; i < files.length;i++) {
   formData.append('files[]', files[i]);
}

然后,发送这个FormData对象

xhr.send(formData);

七、跨域请求(CORS)

XMLHttpRequest对象,可以向不同的域名的服务器发送HTTP请求,这叫做"跨域资源共享"(Cross-Origin ResourceSharing,简称CORS)

使用“跨域资源共享”的前提,是浏览器必须支持这个功能,而且服务器必须同意这种“跨域”。如果能够满足上面的条件,则代码的写法与不跨域的请求完全一样

xhr.open("GET", "'http://other.server/and/path/to/script'");

主流浏览器都支持CORS,IE 10也支持这个功能。服务器端的设置,请参考《Server-Side Access Control》

八、接受二进制数据(方法A:改写MIME Type)

老版本的XMLHttpRequest对象,只能从服务器取回文本数据(否则它的名字就不用XML起首了),新版本可以取回二进制is护具

这里又分为两种做法。较老的做法是该写数据的MIMEType,经服务器返回的二进制数据伪装成文本数据,并且告诉浏览器这是用户自定义的字符集

xhr.overrideMimeType("text/plain; charset=x-user-defined");

然后,用responseText属性接受服务器返回的二进制数据

var binStr = xhr.responseText;

由于此时,浏览器把它当作文本数据,所以还必须在一个个字节地还原成二进制数据

 for (var i = 0, len = binStr.length; i < len; ++i) {
    var c = binStr.charCodeAt(i);
    var byte = c & 0xff;
  }

最后一行的位运算"c & 0xff",表示在每个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。原因是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。

八、接受二进制数据(方法B:responseType属性)

从服务器取回二进制数据,较新的方法是使用新增的responseType属性。如果服务器返回文本数据,这个属性的值是“TEXT”,这是默认值。较新的浏览器还支持其他值,也就是说,可以接受其他格式的数据

你可以把responseType设为blob,表示服务器传回的是二进制对象

var xhr = new XMLHttpRequest();
xhr.open("GET",  '/path/to/image.png');
xhr.responseType = 'blob'

接受数据的时候,用浏览器自带的Blob对象即可

var blob = new Blob([xhr.response], {type: 'image/png'});

注意,是读取xhr.response,而不xhr.responseText

你还可以将responseType设为arrayBuffer,把二进制数据装在一个数组里。

 var xhr = new XMLHttpRequest();
  xhr.open('GET', '/path/to/image.png');
  xhr.responseType = "arraybuffer";

接受数据的时候,需要遍历这个数组

 var arrayBuffer = xhr.response;
  if (arrayBuffer) {
    var byteArray = new Uint8Array(arrayBuffer);
    for (var i = 0; i < byteArray.byteLength; i++) {
      // do something
    }
  }

更详细的讨论,请看Sending and Receiving Binary Data

九、进度信息

XMLHttpRequest对象,在传输数据的时候,有一个progress事件,用来返回进度信息

它分为上传和下载两种情况,下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload
我们先定义progress事件的回调函数

xhr.onprogress = updateProgress;
xhr.upload,onprogress = updateProgress;

然后,在回调函数里面,使用这个时间的一些属性

function updateProgress(event) {
    if (event.lengthComputable) {
      var percentComplete = event.loaded / event.total;
    }
  }

上面的代码中,evebt.total是需要传输的总字节,event.loaded是已经传输的字节。如果event.lengthComputable为false,则event.total等于0
与progress事件相关的,还有其他五个事件,可以分别指定回调函数

  • load事件: 传输成功完成。
  • abort时间: 传输被用户取消
  • error时间: 传输中出现错误
  • loadStart时间: 传输开始
  • loadEnd时间: 传输结束,但是不知道成功还是失败

十、readyState和常见响应状态码

状态值XMLHttpRequest.readyState
状态值 状态 描述
0 unsent 未调用open()方法
1 opened 已调用open()方法
2 headers_received 已调用send()方法,并且头部和状态可获得
3 loading 下载中;responseTExt属性已经包括部分数据
4 done 数据下载完毕
常见响应状态码XMLHttpRequest.status

笼统地说:1xx表示请求有问题,2XX请求成功,3XX重定向,4XX客户端错误,5XX服务端错误

状态码 状态码介绍
100 客户必须继续发出请求
101 客户要求服务器根据请求转换HTTP协议版本
200 请求成功
201 提示知道新文件的URL
202 接受和处理、但处理未完成
203 返回信息不确定或不完整
204 请求收到,但返回信息为空
205 服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206 服务器已经完成了部分用户的GET请求
300 请求的资源可在多处得到
301 删除请求数据
302 在其他地址发现了请求数据
303 建议客户访问其他URL或访问方式
304 客户端已经执行了GET,但文件未变化
305 请求的资源必须从服务器指定的地址得到
306 前一版本HTTP中使用的代码,现行版本中不再使用
307 申明请求的资源临时性删除
400 错误请求,如语法错误
401 请求授权失败
402 保留有效ChargeTo头响应
403 请求不允许
404 没有发现文件、查询或URl
405 用户在Request-Line字段定义的方法不允许
406 根据用户发送的Accept拖,请求资源不可访问
407 类似401,用户必须首先在代理服务器上得到授权
408 客户端没有在用户指定的时间内完成请求
409 对当前资源状态,请求不能完成
410 服务器上不再有此资源且无进一步的参考地址
411 服务器拒绝用户定义的Content-Length属性请求
412 一个或多个请求头字段在当前请求中错误
413 请求的资源大于服务器允许的大小
414 请求的资源URL长于服务器允许的长度
415 请求资源不支持请求项目格式
416 请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417 服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求
500 服务器产生内部错误
501 服务器不支持请求的函数
502 服务器暂时不可用,有时是为了防止发生系统过载
503 服务器过载或暂停维修
504 关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长
505 服务器不支持或拒绝支请求头中指定的HTTP版本

十一、AJAX的优点

优点

无刷新加载数据,更好的用户体验
减轻服务器负担,按需加载数据

原文链接

XMLHttpRequest Level 2 使用指南
XMLHttpRequest.readyState

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容