xyhthink

AJAX

   

​ 2005年2月,AJAX 这个词第一次正式提出,它是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。

为什么要用AJAX?

  1. 优化了用户体验; 传统的表单数据提交一旦进行数据发送页面会刷新。 AJAX实现了无刷新加载页面。 可以在提交数据过程之中添加更多的优化。
  2. 我们利用AJAX实现前后端分离的开发模式提高了开发效率。 1 : 4 比列配置前端端控制开发时效性。

AJAX 包括以下几个步骤 :

  1. 创建 XMLHttpRequest 实例
  2. 发出 HTTP 请求
  3. 接收服务器传回的数据
  4. 更新网页数据

XMLHttpRequest本身是一个构造函数,可以使用new命令生成实例。它没有任何参数。

1
2
3
4
5
6
7
8
9
10
11
var xhr = new XMLHttpRequest();
//获取到ajax对象
xhr.open('GET', 'http://www.example.com/page.php', true);
//发出 HTTP 请求,三个参数,请求方式GET/POST,请求的地址url, 是否启用异步(默认是true)
xhr.send(data);
//要发送的数据,不发送则填null
xhr.onreadystatechange = handleStateChange;
function handleStateChange() {
// ...
}
//指定回调函数,监听通信状态(readyState属性)的变化。

​ 一旦XMLHttpRequest实例的状态发生变化,就会调用监听函数handleStateChange

​ 一旦拿到服务器返回的数据,AJAX 不会刷新整个网页,而是只更新网页里面的相关部分,从而不打断用户正在做的事情。

AJAX 只能向同源网址(协议、域名、端口都相同)发出 HTTP 请求,如果发出跨域请求,就会报错。

XMLHttpRequest对象简单用法的完整例子

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://localhost/gp12/0710/01ajax.txt");
xhr.send(null);
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200){
document.body.innerHTML = xhr.responseText;
}
}

XMLHttpRequest 的实例属性

XMLHttpRequest.readyState

XMLHttpRequest.readyState返回一个整数,表示实例对象的当前状态。该属性只读。它可能返回以下值。

  • 0,表示 XMLHttpRequest 实例已经生成,但是实例的open()方法还没有被调用。
  • 1,表示open()方法已经调用,但是实例的send()方法还没有调用,仍然可以使用实例的setRequestHeader()方法,设定 HTTP 请求的头信息。
  • 2,表示实例的send()方法已经调用,并且服务器返回的头信息和状态码已经收到。
  • 3, 表示正在接收服务器传来的数据体(body 部分)。这时,如果实例的responseType属性等于text或者空字符串,responseText属性就会包含已经收到的部分信息。
  • 4,表示服务器返回的数据已经完全接收,或者本次接收已经失败。

​ 每当实例对象发生状态变化,它的readyState属性的值就会改变。这个值每一次变化,都会触发readyStateChange事件。

XMLHttpRequest.response

XMLHttpRequest.response属性表示服务器返回的数据体(即 HTTP 回应的 body 部分)。它可能是任何数据类型,比如字符串、对象、二进制对象等等,具体的类型由XMLHttpRequest.responseType属性决定。该属性只读。

XMLHttpRequest.responseType

XMLHttpRequest.responseType属性是一个字符串,表示服务器返回数据的类型。这个属性是可写的,可以在调用open()方法之后、调用send()方法之前,设置这个属性的值,告诉服务器返回指定类型的数据。如果responseType设为空字符串,就等同于默认值text

XMLHttpRequest.responseType属性可以等于以下值。

  • “”(空字符串):等同于text,表示服务器返回文本数据。
  • “arraybuffer”:ArrayBuffer 对象,表示服务器返回二进制数组。
  • “blob”:Blob 对象,表示服务器返回二进制对象,比如图片文件。
  • “document”:Document 对象,表示服务器返回一个文档对象。
  • “json”:JSON 对象。
  • “text”:字符串。

如果将这个属性设为ArrayBuffer,就可以按照数组的方式处理二进制数据。

如果将这个属性设为json,浏览器就会自动对返回数据调用JSON.parse()方法。

XMLHttpRequest.responseText

XMLHttpRequest.responseText属性返回从服务器接收到的字符串,该属性为只读。只有 HTTP 请求完成接收以后,该属性才会包含完整的数据。

1
2
3
4
5
xhr.onload = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};

XMLHttpRequest.responseXML

XMLHttpRequest.responseXML属性返回从服务器接收到的 HTML 或 XML 文档对象,该属性为只读。如果本次请求没有成功,或者收到的数据不能被解析为 XML 或 HTML,该属性等于null

​ 该属性生效的前提是 HTTP 回应的Content-Type头信息等于text/xmlapplication/xml。这要求在发送请求前,XMLHttpRequest.responseType属性要设为document

​ 该属性得到的数据,是直接解析后的文档 DOM 树。

1
2
3
4
5
6
7
8
9
10
var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);
xhr.send(null);
xhr.responseType = 'document';
xhr.overrideMimeType('text/xml');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseXML);
}
};

XMLHttpRequest.status,XMLHttpRequest.statusText

XMLHttpRequest.status属性返回一个整数,表示服务器回应的 HTTP 状态码。

  • 200, OK,访问正常
  • 301, Moved Permanently,永久移动
  • 302, Moved temporarily,暂时移动
  • 304, Not Modified,未修改
  • 307, Temporary Redirect,暂时重定向
  • 401, Unauthorized,未授权
  • 403, Forbidden,禁止访问
  • 404, Not Found,未发现指定网址
  • 500, Internal Server Error,服务器发生错误

只有2xx和304的状态码,表示服务器返回是正常状态。

1
2
3
4
5
6
7
if (xhr.readyState === 4) {  //可以判断是否出错
if ( (xhr.status >= 200 && xhr.status < 300) || (xhr.status === 304) ) {
// 处理服务器的返回数据
} else {
// 出错
}
}

XMLHttpRequest.statusText属性返回一个字符串,表示服务器发送的状态提示。不同于status属性,该属性包含整个状态信息,比如“OK”和“Not Found”。在请求发送之前(即调用open()方法之前),该属性的值是空字符串;如果服务器没有返回状态提示,该属性的值默认为“OK”。该属性为只读属性。

XMLHttpRequest.timeout,XMLHttpRequestEventTarget.ontimeout

XMLHttpRequest.timeout属性返回一个整数,表示多少毫秒后,如果请求仍然没有得到结果,就会自动终止。如果该属性等于0,就表示没有时间限制。

XMLHttpRequestEventTarget.ontimeout属性用于设置一个监听函数,如果发生 timeout 事件,就会执行这个监听函数。

XMLHttpRequest 的实例方法

XMLHttpRequest.open()

XMLHttpRequest.open()方法用于指定 HTTP 请求的参数,或者说初始化 XMLHttpRequest 实例对象。它一共可以接受五个参数。

1
2
3
4
5
6
7
void open(
string method,
string url,
optional boolean async,
optional string user,
optional string password
);
  • method:表示 HTTP 动词方法,比如GETPOSTPUTDELETEHEAD等。
  • url: 表示请求发送目标 URL。
  • async: 布尔值,表示请求是否为异步,默认为true。如果设为false,则send()方法只有等到收到服务器返回了结果,才会进行下一步操作。该参数可选。由于同步 AJAX 请求会造成浏览器失去响应,许多浏览器已经禁止在主线程使用,只允许 Worker 里面使用。所以,这个参数轻易不应该设为false
  • user:表示用于认证的用户名,默认为空字符串。该参数可选。
  • password:表示用于认证的密码,默认为空字符串。该参数可选。

XMLHttpRequest.send()

XMLHttpRequest.send()方法用于实际发出 HTTP 请求。它的参数是可选的,如果不带参数,就表示 HTTP 请求只有一个 URL,没有数据体,典型例子就是 GET 请求;如果带有参数,就表示除了头信息,还带有包含具体数据的信息体,典型例子就是 POST 请求。

1
2
3
4
5
6
7
8
9
10
// 发送 POST 请求
var xhr = new XMLHttpRequest();
var data = 'email='
+ encodeURIComponent(email)
+ '&password='
+ encodeURIComponent(password);

xhr.open('POST', 'http://www.example.com', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send(data);

XMLHttpRequest.setRequestHeader()

XMLHttpRequest.setRequestHeader()方法用于设置浏览器发送的 HTTP 请求的头信息。该方法必须在open()之后、send()之前调用。

​ 该方法接受两个参数。第一个参数是字符串,表示头信息的字段名,第二个参数是字段值。

1
2
3
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Content-Length', JSON.stringify(data).length);
xhr.send(JSON.stringify(data));

XMLHttpRequest.overrideMimeType()

XMLHttpRequest.overrideMimeType()方法用来指定 MIME 类型,覆盖服务器返回的真正的 MIME 类型,从而让浏览器进行不一样的处理。举例来说,服务器返回的数据类型是text/xml,由于种种原因浏览器解析不成功报错,这时就拿不到数据了。为了拿到原始数据,我们可以把 MIME 类型改成text/plain,这样浏览器就不会去自动解析,从而我们就可以拿到原始文本了。

1
xhr.overrideMimeType('text/plain')  //该方法必须在send()方法之前调用。

​ 修改服务器返回的数据类型,不是正常情况下应该采取的方法。如果希望服务器返回指定的数据类型,可以用responseType属性告诉服务器,就像下面的例子。只有在服务器无法返回某种数据类型时,才使用overrideMimeType()方法。

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
var arraybuffer = xhr.response;
// ...
}
xhr.open('GET', url);
xhr.responseType = 'arraybuffer';
xhr.send();

XMLHttpRequest.abort()

XMLHttpRequest.abort()方法用来终止已经发出的 HTTP 请求。调用这个方法以后,readyState属性变为4status属性变为0

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.example.com/page.php');
setTimeout(function () {
if (xhr) {
xhr.abort();
xhr = null;
}
}, 5000);// 在发出5秒之后,终止一个 AJAX 请求。

load 事件、error 事件、abort 事件

load事件表示服务器传来的数据接收完毕,error 事件表示请求出错,abort 事件表示请求被中断(比如用户取消请求)。

1
2
3
xhr.addEventListener('load', transferComplete);
xhr.addEventListener('error', transferFailed);
xhr.addEventListener('abort', transferCanceled);

AJAX 封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
ajax(url ,
{
data,
type ,
dataType,
callback
}
=
{
type : "GET" ,
data : {} ,
dataType : "text",
callback : "callback"
})
{

if(dataType === "jsonp"){
return Utils.jsonp( url , data , callback)
}
return new Promise( function(resolve , reject){
var xhr = null;
if(XMLHttpRequest){
xhr = new XMLHttpRequest();
}else{
xhr = new ActiveXObject("Mricosoft.XMLHTTP");
}
if(xhr === null) throw "浏览器不支持ajax";

var dataStr = "";
for(var attr in data){
dataStr += (dataStr.length > 0 ? "&" : "") + attr + "=" + data[attr];
}

type === "GET" ? url += (/\?/.test(url) ? "&" : "?") + dataStr : "";
xhr.open( type ? type : "GET" , url );
type === "POST" ? xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"): "";
xhr.send( type === "POST" ? dataStr : null );
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
let res = xhr.responseText;
switch(dataType){
case "text" :res = typeof res === "string" ? res : JSON.stringify(res);
break;
case "json" :res = typeof res === "string" ? JSON.parse(res) : "";
break;
}
resolve(res);
}
}

// 设置超时;
setTimeout(function(){
reject(xhr,"timeout");
},8000)
})
}

AJAX在使用中也带来了一些问题

  1. SEO优化相当差。 不执行JS无法让数据渲染到页面上,导致程序SEO优化很差。 比如京东在商品列表渲染时为了更优的SEO优化, 规避使用ajax。

  2. 没有 history 没法回退或者前进。可以通过技术手段进行弥补;

  3. 兼容性问题。 IE8 + 浏览器支持。

参考文献

 评论


Power by Yuhangxie , 总访问量为 次 。
载入天数...载入时分秒...
京ICP备19024986号