Appearance
ajax
什么是 ajax?
async javastctip and xml, 异步的 js 和 xml
xml: 可扩展的标记语言
作用是通过存储数据的(通过自己扩展的标记名称清晰的展示出来数据结构)
ajax 值所以称为异步的 js 和 xml, 主要原因是:当初最开始用 ajax 实现客户端和服务器端数据通信的时候,传输的数据格式一般都是 xml 格式的数据,我们把他们称为异步 js 和 xml(现在一般都是基于 json 格式进行数据传输)
xml
<?xml version='1.0' encoding='UTF-8'?>
<root>
<student>
<name>张三</name>
<age>25</age>
<score>
<english>90</english>
<math>90</math>
<chinese>90</chinese>
</score>
</student>
</root>
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
异步的 js
这里的异步不是 ajax 只能基于异步进行请求(虽然建议都是使用异步变成),这里的异步特指的是局部刷新
局部刷新 vs 全局刷新
在非完全前后端分离项目中,前端开发只需要完成页面的制作,并且把一些基础的人机交互效果使用 js 完成即可,页面中需要动态呈现内容的部分,都是交给后台开发工程师做数据绑定和基于服务器进行渲染的(服务器端渲染)
【优势】
- 动态展示的数据在页面的原代码中可以看见,有利于 seo 优化推广(有利于搜索引擎的收录和抓取)
- 从服务器获取的结构就已经是最后要呈现的结果了,不需要客户端做额外的事情,所以也没加速快(前提是服务器端处理的速度够快,能够处理过来),所以类似于京东、淘宝这些网站,首屏数据一般都是由服务器渲染的
【弊端】
- 实时更新的数据,每一次想要展示最新的数据,页面都要重新的刷新一次,这样肯定不行
- 都交给服务器端做数据渲染,服务器端的压力太大,如果服务器处理不过来,页面呈现的速度更慢(所以京东、淘宝这类网站,除了首屏是服务器端渲染的,其他屏一般都是客户端做数据渲染绑定)
- 这种模式不利于开发(开发效率低)

目前市场上大部分项目都是前后端完全分离的项目(也有非完全前后端分离的)
前后端完全分离
前后端完全分离的项目,页面中需要动态绑定的数据是交给客户端完全渲染的
- 想服务器端发送 ajax 请求
- 把从服务器端获取的数据解析处理,拼接成为我们需要展示的 html 字符串
- 把拼接好的字符串替换页面中某一部分的内容(局部刷新), 页面整体不需要重新加载,局部渲染极客
【优势】
- 我们可以根据需求,任意修改页面中某一部分的内容(例如实时刷新), 整体页面不刷新,性能好,体验好(所有表单验证,需要实时刷新的等需求都要基于 ajax 实现)
- 有利于开发,提高开发的效率
- 前后端的完全分离,后台不需要考虑前端如何实现,前端也不需要考虑后台用什么技术,真正意义上实现了技术的划分
- 可以同时进行开发:项目开发开始,首先制定前后端数据交互的结构文档(文档中包含了,调用哪个接口或者那些数据等协议规范), 后台吧接口线写好(目前很多公司也需要前端自己拿 node 来模拟这些接口),客户端按照接口调取极客,后端再去实现接口功能极客
【弊端】
- 不利于 seo 优化:第一次从服务器端获取的内容不包含需要动态绑定的数据,所以也没的原代码中没有这些内容,不利于 seo 收录,后期听过 js 添加到页面中的内容,并不会写在页面的源代码中(是源代码不是页面结构)
- 交由客户端渲染,首先需要把页面呈现,然后通过 js 的异步 ajax 请求获取数据,然后数据绑定,浏览器在动态增加部分重新渲染,无形中浪费了一些时间,没有服务器端渲染页面呈现速度快

ajax 请求
javascript
let xhr = new XMLHttpRequest();
// 不兼容ie6以及更低版本的浏览器(ie6 activeXobject)
// 打开请求地址(可以理解为一些基础配置,但是并没有发送请求呢)
xhr.open([method],[url],[async],[username],[user password]);
// 监听ajax改变,获取响应信息(获取响应头信息,获取响应主体信息)
xhr.onreadystatechange=()=>{
if(xhr.readyState===4 && xhr.readyState===200){
let result = xhr.responseText;// 获取响应主体中的内容
}
}
// 发送ajax请求(括号中传递的信息内容是请求主体的内容)
xhr.send(null)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
分析第二部分的细节点
javascript
xhr.open([method],[url],[async],[username],[user password]);
1
ajax 请求方式(method)
get 系列的请求
get
delete
head
...
post 系列的请求(推送)
post
put: 想服务器中增加指定的资源文件
...
不管哪一种请求方式,客户端可以吧信息传递给服务器,服务器也可以吧信息返回给客户端,只要 get 系列一般以获取为主(给的少)
- 我们想获取一些动态展示的信息,一般使用 GET 请求,因为只需要向服务器发送请求,告诉服务器端想要什么,服务器端就会把需要的数据返回
- 在实现注册功的时候,我们需要把客户端输入信息发送给服务器进行存储,服务器一般返回成功是成功等状态,此时我们一般都基于 post 请求完成
- ....
get 系列请求和 post 系列请求,在项目是在中存在很多的区别
- get 请求传递给服务器的内容一般贸易 post 请求传递给服务器的内容多
- 原因:get 请求传递给服务器内容一般都是基于url 地址问号传递参数 来实现的,而实现的,而 post 请求一般都是基于设置请求主体来实现的。浏览器都已自己的关于 url 的最大长度限制(谷歌:8kb、火狐:7kb、ie:2kb) 超过限制长度的部分,浏览器会自动截取掉,导致传递给服务器的数据缺失
- 理论上 post 请求通过主体传递是没有大小限制,真实项目中为了保证传输的速度,我们会限制大小(例如:上传的资料或者图片我们会做大小的限制)
- get 请求容易出现缓存(这个缓存不可控:一般我们都不需要),而 post 不会出现缓存(除非自己做特殊处理)
- 原因:get 是通过 url 问号传参传递给服务器信息,二 post 是设置请求主体
- 设置请求主体不会出现缓存,但是 url 传递参数就会了
javascript
setTimeout(() => {
$.ajax({
url: "getList?lx=news",
success: (result) => {
// 第一次请求数据回来,间隔一分钟后,浏览器又发送一次请求,
// 但是新发送,不管是地址还是传递的参数都和第一次不一样,
// 浏览器很有可能会把上一次数据获取,而不是获取新的数据
},
});
}, 60000);
// 解决方案:每一次重新请求的时候,在URL的末尾追加一个随机数,保证每一次请求的地址不完全一直
// 就可以避免是从缓存中读取的数据
setTimeout(() => {
url: "getList?lx=news_=" + Math.random();
success: (result) => {};
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
3.GET 请求没有 post 请求安全 (post 也并不是十分安全,只是相对安全) 原因:还是因为 get 是 url 传递给服务器有一种比较简单的黑客技术:url 劫持,也就是可以客户端传递给服务器劫持掉,导致信息泄露
url
请求数据的地址 (api 地址),真实项目中,后台开发工程师会编写一个 api 文档,在 api 文档中汇总了获取那些数据需要使用哪些地址,我们按照文档操作即可
async
异步 (sync 同步),设置当前 ajax 请求是异步还是同步的,不写默认是异步 (true),如果设置 false,则代表当前请求是同步的
用户名和密码这两个参数一般不用,如果你请求的 url 地址所在服务器设定了访问权限,则需要我们提供通行的用户名和密码才可以(一般服务器都可以允许匿名访问的)
AJAX 状态码
xhr.readyState
- unsent 未发送,只要创建一个 ajax 对象,默认值是零
- opened 我们已经执行了 xhr,open 这个操作
- headers_resceived 当前 ajax 的请求已经发送,并且已经接收到服务器端返回的响应头信息了
- loading 响应主体内容正在返回的路上
- done 响应主体内容已经返回到客户端
HTTP 网络状态码
记录了当前服务器返回信息的状态
xhr.status
- 200 成功,一个完整的 http 事务完成了(以 2 开头的状态码一般性都是成功)
- 3 开头一般也是成功,只不过是服务器做了特殊的处理
- 301 moved permanently 永久转移(永久重定向)
- 302 move temporarily 临时转移(临时重定向,新的 http 版本中任务 307 是临时重定向)
- 一般用于服务器的负载均衡:当前服务器处理不了,我把当前请求临时交给其他的服务器处理(一般图片请求经常出现 302, 很多公司都有单独的图片服务器)
- 304 not modified 从浏览器缓存中获取数据
- 把一些不经常更新的文件或者内容缓存到浏览器中,下一次从缓存中获取,减轻服务器压力,也提高页面加载的速度
- 4 开头的,一般性都是失败的,而且客户端的问题偏大
- 400: 请求参数错误
- 401: 无权限访问
- 404: 访问地址不存在
- 5 开头的,一般都是失败,而且服务器的问题偏大
- 500:internal Server Error 未知的服务器错误
- 503:Service Unavailable 服务器超负债
- ...
ajax 中总共支持几个方法
javascript
let xhr = new xmlHttpReques();
console.dir(xhr);
1
2
2
属性
readyState: 存储的是当前 ajax 的状态 response/responseText/responseXML : 都是用来接收服务器返回的响应主体的内容,只是更具服务器返回内容的格式不一样,我们使用不同的属性接收即可 responseText 是最常见的,接收到结果是字符串格式的(一般服务器返回的数据都是 json 格式字符串) responXML: 偶尔会用到,如果服务器返回的是 xml 文档数据,我们需要使用这个属性接收 status: 记录了服务器返回的 http 状态码 statusText: 对返回状态码的描述 timeout: 设置当前 ajax 请求的超时时间,假设我们设置时间为 3000(MS),从 AJAX 请求发送开始,3 秒后响应主体内容还没有返回,浏览器会把当前 ajax 请求强行断开
方法
abor(): 强行终端 ajax 请求 getAllResponseHeaders(): 获取全部的响应头信息(获取的结果是一丢字符串文本) getResponseHeader(key): 获取指定属性名的响应头部信息,例如:xhr.getResponseHeader('data') 获取响应头中存储的服务的时间 open(): 打开一个 url 地址 overridMimeType(): 重写数据的 MIME 类型 send(): 发送 ajax 请求(括号中书写的内容是客户端请求主体吧信息传递给服务器) setRequestHeader(key,value): 设置请求头信息(可以是设置自定义请求信息)
事件
onabort: 当 ajax 被终端请求触发这个时间 onreadstatechange:ajax 状态发烧改变,会触发这个事件 ontimeout: 当 AJAX 请求超时,会触发这个事件 ...
javascript
let xhr = new XMLHttpRequest(();
xhr.open('get','temp.json?_='+Math.random(),true);
xhr.setRequesHeader('cookie','xxx'); // => 设置请求内容不能出现中文汉字
xhr.timeout = 10;
xhr.ontimeout=()=>{
console.log('当前请求已经超时');
xhr.abort();
}
xhr.onreadystatechange = () =>{
let {readyState:state,status} = xhr;
// 说明请求数据成功了
if(!/^(2|3)\d{2}$/.test(status)) return
// 在状态为2的时候就获取响应头信息
if(state === 2){
let headerAll = xhr.getAllResponseHeaders(),
serverDate = xhr.getResponseHeader('date');// 获取的服务时间是格林尼治时间(相比北京时间差不多差8小时)
console.log(headerAll,new Date(serverDate));
return;
}
// 在状态为4的时候就获取响应头信息已经回来了
if(state === 4){
let valueText = xhr.responseText,// 获取到的结果一般都是json字符串(可以时间json.parse把其转换成json对象)
valueXML = xhr.responseXML; // 获取到的结果是xml格式的数据,(可以通过xml的一些常规操作获取存储的指定信息)
// 如果服务器返回的是xml文档,responseText获取的结果是字符串,而responseXML获取的是标准xml文档
console.log(valueText,valueXML);
}
}
xhr.send('name=wjw&age=23&sex=man')
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
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
AJAX 中的同步和异步编程
javascript
let xhr = new XMLHttpRequest();
xhr.open("get", "temp.json", false);
xhr.onredystatechange = () => {
console.log(xhr.readySate);
};
xhr.send();
// 只输出一次结果4
1
2
3
4
5
6
7
2
3
4
5
6
7
javascript
let xhr = new XMLHttpRequest();
xhr.open("get", "temp.json", false);
xhr.send(); // => 同步开始发送ajax请求,开启ajax任务,在任务没有完成之前,什么事情都做不了
// 下面绑定时间也做不了 => loading => 当readyState ===4 的是ajax任务完成,开始执行下面的操作
xhr.onreadystatechange = () => {
console.log(xhr.readySate);
};
// 绑定方法之前状态已经为4了,此时ajax的状态不会再改吧其他值,所以事件永远不会被处罚
// 一次都没有执行方法(使用ajax同步编程,不要把send放在事件监听前
// 这样我们无法在绑定方法中获取响应主体的内容)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
javascript
let xhr = new XMLHttpRequest();
// 下面绑定时间也做不了 => loading => 当readyState ===4 的是ajax任务完成,开始执行下面的操作
xhr.onreadystatechange = () => {
console.log(xhr.readySate);
if (xhr.readySate === 1) {
xhr.setRequestHeader("aaa", "bbb");
}
};
xhr.open("get", "temp.json", false);
// xhr.readyState === 1 AJAX特殊处理的一件事:执行OPEN状态变为1,会主动把之前监听的方法执行一次
// 然后再去执行SEND
xhr.send();
// xhr.redayState === 4 AJAX任务借宿,主任务队列完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
AJAX 类库的封装
JQ 中的 AJAX
javascript
$.ajax({
url:'xxx.txt',
method:'get',
dataType:'json',
cache:false,
data:null,
async:true,
success:function(result){
},
error:funciton(msg){
},
complate:function(msg){
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
url
请求 api 地址
method
请求方法 get/post.. 在老板的 jq 中使用是 type,使用 type 和 method 相同效果
dataType
dataType 只是我们预设获取结果的类型不会影响服务器的返回(服务器端一般给我们返回的都是 json 格式的字符串), 如果我们预设是 json, 那么类库中将吧服务器返回的字符串转换为 json 对象,如果我们预设是 text(默认值),我们把服务器获取的结果直接拿过来操作即可,我们预设的值还可以 xml 等
cache
设置是否清楚缓存,只对 get 系列请求有作用,默认是 true 不清除缓存,手动设置 false,jq 类库在请求 url 的末尾最佳一个随机数来清楚缓存
data
我们通过 data 可以把一些信息传递给服务器,get 系列请求会把 data 中的内容拼接在 url 的末尾通过问号传参的方式给服务器,post 系列请求会把内容请求放在主题传递给服务器;data 的值可以设置为两种格式,字符串、对象,如果是字符串,设置的值是传递给服务器的就是什么,如果设置成对象,jq 会把对象变为 xxx=xxx&xx=xx, 这样来数据传递
async
设置同步或者异步,默认是 true 代表异步,false 代表同步
success
dangajax 请求成功后 redayState===4&&statue 是以 2 或者 3 开头的 请求成功后 jq 会把传递的回调函数执行,并且获取的结果当做实参传递给回调函数 (result 就是我们从服务器获取的结果)
error
请求错误触发回调函数
complate
不管请求还是错误的还是正确的都会触发这个回调函数(他就是完成的意思)
....
封装自己的 AJAX 库
- url
- method/type
- data
- dataType
- async
- cache
- success
javascript
~funcction(){
class ajaxClass {
// send ajax
init() {
let xhr = new XMLHttpRequest();
xhr.onreadustatechange = () => {
if (!/^[23]\d{2}$/.test(xhr.status)) return;
if (xhr.redayState === 4) {
let result = xhr.responseText;
// DATA-TYPE
switch (this.dataType.toUpperCase()) {
case 'TEXT':
break;
case 'JSON':
result = JSON.parese(result);
break;
case 'XML':
result = xhr.responseXML;
break;
}
this.success(result);
}
}
// DATA
if (this.data !==null) {
this.formatData();
if (this.idGET) {
this.url +=this.querySymbol()+this.data;
this.data = null;
}
}
// CACHE
this.isGET ? this.cache();
xhr.open(this.method, this.url, this.async);
xhr.send();
}
cacheFn() {
// THIS:EXAMPLE
!this.cache ? this.url += `${this.querySymbol()}_=${Math.random()}` : null;
}
querySymbol() {
// THIS:EXAMPLE
return this.url.indexOf('?') > -1 ? '&' : '?';
}
formatData(){
// THIS:EXAMPLE
if(Object.prototype.toString.call(this.data)==='[Object Object]'){
let obj = this.data,
str = ``;
for (const key in obj) {
if (object.hasOwnProperty(key)) {
str +=`${key}=${obj[key]}`;
}
}
str = str.replace(/&$/g,'');
this.data = str;
}
}
}
let ajax = function () {
};
// init parameters
window.ajax = function ({
url = null,
method = 'GET',
type = 'GET',
data = null,
dataType = 'JSON',
cache = true,
async = ture,
suceess = null
} = {}) {
let _this = new ajaxClass(); // 创建实例
['url', 'method','data','dataType','cache','async','success'].forEach((item)=>{
if (item === 'method') {
_this.method = type === null ? method : type;
return;
}
if (item==='success') {
_this.suceess = typeof success === 'function' ? success : new Function();
}
_this[item] = eval(item);
})
_this.isGET = /^(GET|DELETE|HEAD)$/i.test(example.method);
_this.init();
return _this;
};
}();
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102