从零天梯:Ajax浅析

前言

前段时间群里做知识分享,大豹老师分享了他对Ajax的一些心得体会,当时听的比较入迷,整理了一些笔记,希望对大家有帮助。

知识目录结构

  • Ajax 基础知识
  • jQuery中Ajax的相关用法
  • jQuery中Ajax全局设置和全局事件
  • 表单数据序列化
  • 实际应用中的注意事项
  • 知识扩展
  • 参考资料

1 Ajax 基础知识

1.1Ajax是什么

Ajax的全称是Asyncronous Javascript And XML(异步传输JavaScript+XML)

  • 直白地说,就是没用Ajax的页面,你点一个按钮就要刷新一下页面,尽管新页面上只有一行和当前页面不一样,但还是要无聊地等待页面刷新。
  • 用了Ajax之后再点击,然后页面上的一行就变化了,页面本身不用刷新。(简称页面无刷新数据交互)
  • Ajax只是一种技术,不是某种具体的东西。不同的浏览器有自己的实现的Ajax的组件。
  • XML只是一种数据格式,在这里并不重要,现在大部分人用JSON格式代替XML,原因是JSON更加简洁,解析速度也更快。

总结: 只要是JS调用异步通讯组件并使用格式化的数据来更新web页面上的内容或操作过程,那么我们用的方法就可算是Ajax。

1.2 同步和异步

javascript是单线程的,代码始终自上往下依次执行。

可以异步执行的代码:Ajax、setTimeout、setInterval。

1.3 异步请求有什么用途?

  1. 制作单页面应用,用户操作不进行跳转、每次只更新局部内容
  2. 表单即时校验,如文本框失去焦点立即检验
  3. 进行前后端分离,后端只关注数据
  4. 定时异步请求(轮询),实现伪实时效果,如在线聊天室
  5. 异步加载多级数据,如树形结构、多级联动菜单、分页
  6. ……

问题:前端如何处理大数据?
解析:前端数据再大,还是要向服务器端请求数据,浏览器还是要解析,其实没法从根本上解决问题。如果页面上的dom节点多了,浏览器可能就处理不过来,造成浏览器假死现象。
一个方案就是:异步加载完这些数据,来进行异步处理,这样可以减轻浏览器的压力。

1.4 异步请求的优缺点

优点:
1.不会阻塞当前正在进行的任务。
2.局部刷新,避免页面跳转,用户体验更好
3.减少请求数据的大小,加载更快
4.有利于前后端分离,后端只关注数据

缺陷:
1.毁坏浏览器前进后退按钮的功能
2.不利于SEO
3.无法跨域

这些都有相应的解决方法

1.5 认识XMLHttpRequest对象

我们可以创建一个实例,并在控制台里面打印

1
2
var xhr = new XMLHttpRequest();
console.log(xhr);

认识几个重要的字段,方法。

1
2
3
4
5
6
7
8
9
10
11
12
① 字段
onreadystatechange:null 请求的状态发生变化时的属性
readyState:0 请求的状态
responseText:"" 服务器返回的东西
status:0 对应http状态码
textStatus 会告诉你error的类型

② 原型方法
abort() 取消请求。
open() 建立一个连接
send() 发送请求
setRequestHeader() 设置请求头部

1.6 原生ajax写法

需要注意的是原生XMLHttpRequest不兼容低版本IE6及以下,所以还需要考虑低版本的IE的兼容性。
兼容IE6的写法: ActiveXObject(‘Microsoft.XMLHTTP’)。
兼容IE5的写法: ActiveXObject(‘MSXML2.XMLHTTP’)。

以下是做了兼容性处理的原生请求的创建:

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
function createXMLHTTPRequest() {
//1.创建XMLHttpRequest对象
//这是XMLHttpReuquest对象无部使用中最复杂的一步
//需要针对IE和其他类型的浏览器建立这个对象的不同方式写不同的代码
var xhr;
if (window.XMLHttpRequest) {
//针对FireFox,Mozillar,Opera,Safari,IE7,IE8
xhr = new XMLHttpRequest();
//针对某些特定版本的mozillar浏览器的BUG进行修正
if (xhr.overrideMimeType) {
xhr.overrideMimeType("text/xml");
}
} else if (window.ActiveXObject) {
//针对IE6,IE5.5,IE5
//两个可以用于创建XMLHTTPRequest对象的控件名称,保存在一个js的数组中
//排在前面的版本较新
var activexName = ["Microsoft.XMLHTTP","MSXML2.XMLHTTP"];
for (var i = 0; i < activexName.length; i++) {
try {
//取出一个控件名进行创建,如果创建成功就终止循环
//如果创建失败,回抛出异常,然后可以继续循环,继续尝试创建
xhr = new ActiveXObject(activexName[i]);
if (xhr) {
break;
}
} catch (e) {}
}
}
return xhr;
}

GET请求用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var req = createXMLHTTPRequest();
if (req) {
req.open("GET", "http://test.com/?keywords=test", true);
req.onreadystatechange = function() {
if (req.readyState == 4) {
if (req.status == 200) {
alert("success");
//主动释放,js本身也会回收
xhr = null;
} else {
alert("error");
}
}
}
req.send(null);
}

POST请求用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var req = createXMLHTTPRequest();
if(req){
req.open("POST", "http://test.com/", true);
//post请求需要设置请求头
req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
req.send("keywords=test");
req.onreadystatechange = function(){
if(req.readyState == 4){
if(req.status == 200){
alert("success");
//主动释放,js本身也会回收
xhr = null;
}else{
alert("error");
}
}
}
}

readyState值说明:请求分5个阶段,每个阶段有对应的readyState的值:

  • 0-未初始化,send方法未调用
  • 1-正在发送请求,send方法已调用
  • 2-请求发送完毕,send方法执行完毕
  • 3-正在解析响应内容(可以接收到部分响应数据)
  • 4-响应内容解析完毕(数据接收完毕并且连接已经关闭)

status值说明:通常是用来判断服务器方的状态:

  • 100——客户必须继续发出请求
  • 101——客户要求服务器根据请求转换HTTP协议版本
  • 200——成功
  • 201——提示知道新文件的URL
  • 300——请求的资源可在多处得到
  • 301——删除请求数据
  • 404——没有发现文件、查询或URl
  • 500——服务器产生内部错误

2 jQuery中的ajax

jQuery中的ajax原理就是对原生的请求方法做了进一步封装和兼容性处理,包装成常用的方法:

1
2
3
4
5
6
$.ajax()
$.get()
$.post()
$.getJSON()
$.getScript()
$.fn.load()
1
2
3
4
5
6
7
8
9
10
11
12
13
$.ajax({
url:'请求地址',
type:'GET/POST',
async: true/false, //是否异步
data: {},//发送的数据
timeout: '5000',//超时时间
dataType: 'json/xml/html/script/json/jsonp/text'
//返回的数据格式
beforeSend: function(xhr){},//发送请求前
success: function(data, textStatus, jqXHR){},//请求成功
error: function(xhr, textStatus){},//请求失败
complete: function(xhr, testStatus){},//请求结束
})

通常情况下使用$.ajax,因为他稍微更底层一点,可配置性高一点,可控性也高一点,效率也高一些。

3 Ajax中的全局配置和全局事件

1
2
3
4
5
6
7
8
9
10
11
12
$.ajaxSetup({
type: 'POST',
timeout:'6000',
data: {name: 'abc'},
dataType: 'json',
beforSend: function() {
console.log('loading...');
},
error: function() {
alert('请求失败,请重试!');
}
});
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
<script type="text/javascript">
$(document).ajaxStart(function() {
/* Stuff to do when an AJAX call is started and no other AJAX calls are in progress */;
});

$(document).ajaxSend(function(event, xhr, settings) {
/* stuff to do before an AJAX request is sent */;
});

$(document).ajaxSuccess(function(event, xhr, settings) {
/* executes whenever an AJAX request completes successfully */
});

$(document).ajaxError(function(event, xhr, settings, thrownError) {
/* Stuff to do when an AJAX call returns an error */;
});

$(document).ajaxComplete(function(event, xhr, settings) {
/* executes whenever an AJAX request completes */
});

$(document).ajaxStop((function() {
/* stuff to do when all AJAX calls have completed */;
});
</script>

可以通过Ajax全局事件写一个漂亮的显示请求进度的DEMO

4 表单数据序列化

作用:
1.异步提交表单,免去跳转
2.快速获取表单数据
jQuery中的方法
serializ()//序列化为字符串
serializeArray()//序列化为数组

这两个不是jQuery中的方法
IE7以下需要引入JSON2文件
JSON对象呢在HTML5里面已经列为标准了呢。IE6还不能支持。所以还需要依赖JSON2文件
JSON.parse()//json字符串转化为json对象
JSON.stringify()//json对象转为json字符串

5 实际应用中的注意事项

5.1 函数return异步数据,取不到的问题

可以设置为同步请求,或者返回promise。

5.2 同步Ajax请求造成的UI线程阻塞问题

一个浏览器嘛,他分为两个引擎,一个是js引擎用来解析你的js代码,比方说chrome的js引擎是v8,UI引擎是webkit,一个浏览器么,一个js引擎,一个ui引擎。这两个是没法同时进行的。一个运行的时候,他会阻塞吊另一个。什么意思呢。发送同步请求的时候,比如2秒钟的时候,js引擎要工作2s钟的时间,他会把ui引擎给阻塞掉,所以gif图片他是需要ui引擎来渲染的,所以他会阻塞掉的。(阻塞时,js,animate照常运行,但是页面呈现出的是2s后的效果)。为什么我们平时感受不到js引擎把UI引擎给阻塞掉了?因为同步的代码是非常快的。第一个例子执行100万次才10几毫秒,所以你感受不到。但是2s种你就能做好多事情。

5.3 为Ajax设置时间超时

参考Ajax全局配置章节。

5.4 判断error类型

error的类型可能有:
timeout 超时
error 获取不到具体错误(请求时浏览器刷新报error错误)
notmodified 返回304
parsererror 解析xml或json错误
abort 请求取消

6 扩展知识

  • HTML5的XMLHttpRequest2
  • promise规范和jQuery的Deffered对象
  • pjax
  • 跨域请求
  • Fetch

7 参考资料