乐趣区

AJAX基础知识及核心原理详解。前后端分离和不分离的优势与弊端

AJAX 基础知识及核心原理解读
AJAX 基础知识
什么是 AJAX?async javascript and xml 异步的 JS 和 XML

XML:可扩展的标记语言
作用:是用来存储数据的(通过自己扩展的标记名称清晰地展示出数据结构)ajax 之所以称为异步的 js 和 xml,主要原因是:以前最开始使用 ajax 实现客户端和服务端数据通信的时候,传输数据的格式一般都是 xml 格式的数据,我们把他称之为异步的 js 和 xml(现在一般都是基于 JSON 格式来进行数据传输的)

<?xml version=”1.0″ encoding=”UTF-8″?>
<root>
<student>
<name> 海洋 </name>
<age>10</age>
<score>
<deutsch>100</deutsch>
<IT>100</IT>
<english>100</english>
</score>
</student>
</root>
异步的 JS
这里的异步不是说 ajax 只能基于异步进行请求(虽然建议都是使用异步编程),这里的异步特指的是 局部刷新
局部刷新 VS 全局刷新

全局刷新:在非完全前后端分离的项目中,前端开发只需要完成页面的制作,并且把一些基础的人机交互效果使用 js 完成即可,页面中需要动态呈现内容的部分,都是交给后台开发工程师做数据绑定和基于服务器进行渲染的(服务器端渲染)

【优势】

动态展示的数据在页面的源代码中可以看见,有利于 SEO 优化推广(有利于搜索引擎的收录和抓取)
从服务器端获取的结果已经是解析渲染完成的了,不需要客户端再去解析渲染了,所以页面加载速度快(前提是服务器端处理的速度够快,能够处理过来),所以类似于京东,淘宝这些网站,首屏数据一般都是由服务器端渲染的

【弊端】

如果页面中存在实时更新的数据,每一次想要展示最新的数据,页面都要重新刷新一次,这样肯定不行,非常耗性能
都交给服务器端做数据渲染,服务器端的压力太大,如果服务器处理不过来,页面呈现的速度更慢(所以像京东和淘宝这类的网站,除了首屏是服务器端渲染的,其他屏一般都是客户端做数据渲染绑定的)
这种模式不利于开发,(开发效率低)

局部刷新
目前市场上大部分项目都是前后端完全分离的项目(也有非完全前后端分离的占少数)
前后端完全分离的项目,页面中需要动态绑定的数据是交给客户端完成渲染的

向服务器端发送 AJAX 请求
把从服务器端获取的数据解析处理,拼接成我们需要展示的 HTML 字符串
把拼接好的字符串替换页面中的某一部分内容(局部刷新),页面不需要整体重新加载,局部渲染即可

【优势】

我们可以根据需求,任意修改页面中的某一部分内容(例如实时刷新),整体页面不刷新,性能好,体验好(所有表单验证,需要实时刷新的等需求都要基于 AJAX 实现)
有利于开发,提高开发效率 1)前后端的完全分离,后台不需要考虑前端如何实现,前端也不需要考虑后台用什么技术,真正意义上实现了技术的划分
2)可以同时进行开发:项目开发开始,首先制定前后端数据交互的接口文档(文档中包含了,调取哪个接口或者哪些数据等协议规范),后台把接口先写好(目前很多公司也需要前端自己拿 NODE 来模拟这些接口),客户端按照接口调取即可,后台再去实现接口功能即可

【弊端】

不利于 SEO 优化:第一次从服务器端获取的内容不包含需要动态绑定的数据,所以页面的源代码中没有这些内容,不利于 SEO 收录,后期通过 JS 添加到页面中的内容,并不会写在页面的源代码中(是源代码不是页面结构)
交由客户端渲染,首先需要把页面呈现,然后在通过 JS 的异步 AJAX 请求获取数据,在进行数据绑定,浏览器再把动态增加的部分重新渲染,无形中浪费了一些时间,没有服务器端渲染页面呈现速度快

基于原生 JS 实现 AJAX
// 创建一个 AJAX 对象
let xhr = new XMLHttpRequest(); // 不兼容 IE6 及更低版本浏览器(IE6:ActiveXObject)

// 打开请求地址 (可以理解为一些基础配置,但是并没有发送请求呢)
xhr.open([method],[url],[async],[userName],[passWord]);

// 监听 AJAX 状态改变,获取响应信息(获取响应头信息,获取响应主体信息)
xhr.onreadystatechange = ()=>{
if(xhr.readyState === 4 && xhr.status === 200){
let result = xhr.responseText; // 获取响应主体中的内容
}
};

// 发送 AJAX 请求 (括号中传递的内容就是请求主体的内容)
xhr.send(null);
分析第二步中的细节点

xhr.open([method],[url],[async],[userName],[passWord])
[AJAX 请求方式]

GET 请求系列(获取)

get
delete:从服务器上删除某些资源文件
head:只想获取服务器返回的响应头信息(响应主体不需要获取)

POST 请求系列(推送)

post
put:向服务器中增加指定的资源文件

不管哪一种请求方式,客户端都可以把信息传递给服务器端,服务器端也可以把信息返回给客户端,只是 GET 系列一般以获取为主(给的少,拿回来的多),而 POST 系列一般以推送为主(给的多,拿回来的少)
1)我们想要获取一些动态展示的信息,一般使用 GET 请求,因为只需要向服务器端发送请求,告诉服务器端我们想要什么,服务器端就会把需要的数据返回
2)在实现注册功能的时候,我们需要把客户输入的信息发送给服务器进行存储,服务器一般返回成功或失败等状态,此时我们一般都是基于 POST 请求完成的

GET 系列请求和 POST 系列请求,在项目实战中存在很多的区别

GET 请求传递给服务器的内容一般没有 POST 请求传递给服务器的内容多原因:GET 请求传递给服务器内容一般都是基于 URL 地址问号传递参数 来实现的,而 POST 请求一般都是基于 设置请求主体 来实现的,各个浏览器都有 URL 最大长度的限制(谷歌:8kb,火狐:7kb,IE:2kb),超出长度部分,浏览器会自动截取掉,导致传递给服务器的数据缺失
理论上 POST 请求通过请求主体传递是没有大小限制的,真实项目中为了保证传输的速率,我们也会限制大小(例如:上传的资料或者图片我们会做大小的限制)

GET 请求很容易出现缓存(这个缓存不可控,一般我们都不需要),而 POST 不会出现缓存(除非自己做特殊处理)原因:GET 是通过 URL 问号传参传递给服务器信息,会出现缓存;而 POST 是设置请求主体,不会出现缓存。

// 每隔一分钟重新请求服务器端最新的数据,然后展示在页面中(页面中某些数据实时刷新)
setTimeout(()=>{
$.ajax({
url: ‘getList?lx = news’,

success: result=>{
// 第一次请求数据回来,间隔一分钟后,浏览器又发送一次请求,但是新发送的请求不论是地址还是传递的参数都和第一次一模一样,浏览器很有可能会把上一次的数据获取,而不是获取最新的数据
}
})
},600)

// 解决方案:在每一次重新请求的时候,在 URL 的末尾追加一个随机数,保证每一次请求的地址不完全一致,就可以避免是从缓存中读取的数据
setTimeout(()=>{
$.ajax({
url: ‘getList?lx = news&_=’ + Math.random(),

success: result=>{

}
})
},600)

GET 请求没有 POST 请求安全(POST 也并不是十分安全,只是相对安全)原因:还是因为 GET 是 URL 传参给服务器
有一种比较简单的黑客技术:URL 劫持,也就是可以把客户端传递给服务器的数据劫持到,导致信息泄露

URL: 请求数据的地址(API 地址),在真实项目中,后台开发工程师会编写一个 API 文档,在 API 文档中汇总了获取哪些数据需要使用哪些地址,我们按照文档操作即可 ASYNC:异步(SYNC 同步),设置当前 AJAX 请求是异步的还是同步的,不写默认是异步(TRUE),如果设置为 FALSE,则代表当前请求是同步的
用户名和密码:这两个参数一般不用,如果你请求的 URL 地址所在的服务器设定了访问权限,则需要我们提供可通行的用户名和密码才可以(一般服务器都是可以匿名访问的)

分析第三步中的细节点

AJAX 状态码:描述当前 AJAX 操作状态的:
xhr.readyState
0:UNSENT 未发送,只要创建一个 AJAX 对象,默认值就是零
1:OPENED 我们已经执行了 xhr.open 这个操作
2:HEADERS_RECEIVED 当前 AJAX 的请求已经发送,并且已经接收到服务器端返回的响应头信息了
3:LOADING 响应主体的内容正在返回的路上
4: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 中其他常用的属性和方法
面试题:AJAX 中总共支持几个方法?
let xhr = new XMLHttpRequest();
console.dir(xhr);

//【属性】
// 1.readyState:存储的是当前 AJAX 的状态码
// response/responseText/responseXML: 都是用来接收服务器返回的响应主体中的内容,只是根据服务器返回内容格式的不一样,我们使用不同的属性接收即可
// responseText 是最常用的,接收的结果是字符串格式的(一般服务器返回的数据都是 JSON 格式字符串)
// responseXML 偶尔会用到,如果服务器返回的是 XML 文档数据,我们需要使用这个属性接收
// status:记录了服务器端返回的 HTTP 状态码
// statusText:对返回的状态码的描述
// timeout:设置当前 AJAX 请求的超时时间,假设我们设置时间为 3000ms,从 AJAX 请求发送开始,3 秒后响应主体内容还没有返回,浏览器会把当前 AJAX 请求任务强制断开

//【方法】
// abort():强制中断 AJAX 请求
// getAllResponseHeaders(): 获取全部的响应头信息(获取的结果是一堆字符串文本)
// getResponseHeader(key): 获取指定属性名的响应头信息,例如:xhr.getResponseHeader(‘date’) 获取响应头中存储的服务器的时间
// open(): 打开一个 URL 地址
// overrideMimeType(): 重写数据的 MIME 类型
// send(): 发送 AJAX 请求(括号中写的是客户端基于请求主体把信息传递给服务器)
// setRequestHeader(key,value): 设置请求头信息(可以是设置自定义请求头信息)

// [事件]
// onabort:当 AJAX 被中断请求时触发这个事件
// onreadystatechange:AJAX 状态发生改变会触发这个事件
// ontimeout: 当 AJAX 请求超时,会触发这个事件
例子:
let xhr = new XMLHttpRequest();
xhr.open(‘get’,’temp.json?_=’ + Math.random(), true);
xhr.setRequestHeader(‘aaa’, ‘123’); // 注意:请求头部的内容不得出现中文汉字。设置请求头信息必须在 OPEN 之后和 SEND 之前

// 设置超时
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 小时), 通过 new Date 可以把这个时间转换为北京时间
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=hy&age=6&sex=man’);

JS 中常用的编码和解码方法

正常的编码解码(非加密)
escape / unescape: 主要就是把中文汉字进行编码和解码(一般只有 JS 语言支持:也经常应用于前端页面通信时候的中文汉字编码)

str = ‘ 你好海洋 哈哈 ’
“ 你好海洋 哈哈 ”
escape(str)
“%u4F60%u597D%u6D77%u6D0B%20%u54C8%u54C8”
unescape(“%u4F60%u597D%u6D77%u6D0B%20%u54C8%u54C8”)
“ 你好海洋 哈哈 ”
encodeURI / decodeURI : 基本上所有的编程语言都支持
str = ‘ 你好海洋 哈哈 ’
“ 你好海洋 哈哈 ”
encodeURI(str)
“%E4%BD%A0%E5%A5%BD%E6%B5%B7%E6%B4%8B%20%E5%93%88%E5%93%88”
decodeURI(“%E4%BD%A0%E5%A5%BD%E6%B5%B7%E6%B4%8B%20%E5%93%88%E5%93%88”)
“ 你好海洋 哈哈 ”
encodeURIComponent / decodeURIComponent 和第二种方式非常类似,区别在于:当我们通过 URL 问号传参的时候,我们传递的参数值还是一个 URL 或者包含很多的特殊字符,此时为了不影响主要的 URL,我们需要把传递的参数值进行编码,使用 encodeURI 不能编码一些特殊字符,所以只能使用恩 codeURLComponent 处理

str = ‘ 你好海洋 哈哈 ’
“ 你好海洋 哈哈 ”
encodeURIComponent(str)
“%E4%BD%A0%E5%A5%BD%E6%B5%B7%E6%B4%8B%20%E5%93%88%E5%93%88”
decodeURIComponent(“%E4%BD%A0%E5%A5%BD%E6%B5%B7%E6%B4%8B%20%E5%93%88%E5%93%88”)
“ 你好海洋 哈哈 ”
let str = ‘http://wudiufo.github.io/?’,
obj = {
name:’haiyang’,
age:’8′;
url:’http://www.haiyang.com/?lx=1′
};
// 需求:把 obj 中的每一项属性名和属性值拼接到 URL 末尾,通过问号传参的方式
for(let key in obj){
str+=`${key}=${encodeURIComponent(obj[key])}&`;
// 不能使用 encodeURI,必须使用 encodeURIComponent,原因是 encodeURI 不能编码特殊的字符
}
console.log(str.replace(/&$/g), ”);

// 后期获取 URL 问号参数的时候,我们把获取的值在依次的解码即可
String.prototype.myQueryUrlParameter=function myQueryUrlParameter(){
let reg=/[?&]([^?&=]+)(?:=([^?&=]*))?/g,
obj={};
this.replace(reg,(…arg)=>{
let [,key,value]=arg;
obj[key]=decodeURIComponent(value); // 此处获取的时候可以进行解码
});
return obj;
}

也可以通过加密的方法进行编码解码

可逆转加密(一般都是团队自己用的规则)

不可逆转加密(一般都是基于 MD5 完成的,可能会把 MD5 加密后的结果二次加密)

AJAX 中的同步和异步编程
AJAX 这个任务:发送请求接收到响应主体内容(完成一个完整的 HTTP 事务)xhr.send() : 任务开始
xhr.readState===4 : 任务结束

let xhr = new XMLHttpRequest();
xhr.open(‘get’, ‘temp.json’, false);
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
xhr.send();
// 只输出一次结果是 4

let xhr = new XMLHttpRequest();
xhr.open(‘get’, ‘temp.json’, false);
xhr.send(); // [ 同步] 开始发送 AJAX 请求,开启 AJAX 任务,在任务没有完成之前,什么事情都做不了(下面绑定事件也做不了)=》loading =》当 readyState=== 4 的时候 AJAX 任务完成,开始执行下面的操作
// readyState===4
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
// 绑定方法之前状态已经为 4 了,此时 AJAX 的状态不会再改变成其他的值了,所以事件永远都不会被触发,一次都没执行方法(使用 AJAX 同步编程,不要把 send 放在事件监听前,这样我们无法再绑定的方法中获取到响应主体的内容)

let xhr = new XMLHttpRequest();
xhr.open(‘get’, ‘temp.json’);
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
xhr.send();
// 输出 3 次,结果分别是 2,3 ,4

let xhr = new XMLHttpRequest();
xhr.open(‘get’, ‘temp.json’);
xhr.send();
// xhr.readyState===1
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
// 2,3,4

let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
xhr.open(‘get’, ‘temp.json’);
xhr.send();
// 1,2,3,4

let xhr = new XMLHttpRequest();
// xhr.readyState===0
xhr.onreadystatechange = () =>{
console.log(xhr.readyState);
};
xhr.open(‘get’, ‘temp.json’,false);
// xhr.readyState===1,AJAX 特殊处理了一件事,执行 OPEN 状态变为 1,会主动把之前监听的方法执行一次,然后再去执行 SEND
xhr.send();
// xhr.readyState===4 AJAX 任务结束,住任务队列完成
// 1,4
实战案例:倒计时抢购
1,结构:
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<meta name=”viewport” content=”width=device-width, initial-scale=1.0″>
<meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
<title>Document</title>
</head>
<body>
<div id=”box”></div>
<script src=”./1.js”></script>
</body>
</html>
2, 交互:
~ function() {
let box = document.getElementById(‘box’);
let serverTime = null;

let fn = () => {
// 1,计算当前时间和目标时间的差值
// new Date():获取的是客户端本机时间(会受到客户端自己调整时间的影响),重要的时间参考不能基于这个完成,不论哪一个客户端都要基于相同的服务器时间计算
// 每间隔一秒钟,我们需要把第一次获取的服务器时间进行累加

serverTime = serverTime + 1000;

let tarTime = new Date(‘2018/12/22 12:00:00’).getTime(),
spanTime = tarTime – serverTime;

// 2, 计算差值中包含多少时分秒
if (spanTime < 0) {
// 已经错过了抢购时间(已经开抢了)
box.innerHTML = ‘ 开枪 ’;
clearInterval(autoTimer);
return;
}

let hours = Math.floor(spanTime / (1000 * 60 * 60));
spanTime -= hours * 3600000;
let minus = Math.floor(spanTime / (1000 * 60));
spanTime -= minus * 60000;
let seconds = Math.floor(spanTime / 1000);
hours < 10 ? hours = ‘0’ + hours : null;
minus < 10 ? minus = ‘0’ + minus : null;
seconds < 10 ? seconds = ‘0’ + seconds : null;

box.innerHTML = ` 距离开枪还剩下 ${hours}:${minus}:${seconds}`;
};

let autoTimer = setInterval(fn, 1000);

// 从服务器端获取服务器时间
let getServerTime = () => {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
// console.log(xhr.readyState);
// HEAD 请求方式,状态码中没有 3(不需要等待响应主体内容)
if (!/^(2|3)\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 2) {
serverTime = new Date(xhr.getResponseHeader(‘date’)).getTime();
fn();
}
};
xhr.open(‘head’, ‘temp.xml’, true);
xhr.send(null);

// 1, 服务器返回的时间在响应头就有,我们只需要获取响应头信息即可,没必要获取响应主体内容,所以请求方式使用 HEAD 即可
// 2,必须使用异步编程:同步编程我们无法再状态为 2 或 3 的时候做一些处理,而我们获取响应头信息,在状态为 2 的时候就可以获取了,所以需要使用异步
// 3, 在状态为 2 的时候就把服务器时间获取到
// 获取服务器时间总会出现时间差的问题,服务器端把时间记录好,到客户端获取到时间有延迟差(例如:服务器返回的时候记录的是 10:00,到客户端获取的时候已经是 10:01,但是客户端获取的结果依然是 10:00,这样就有了 1 秒钟的时间差)【尽可能的减少时间差,是我们优化的全部目的】
};

getServerTime();

}();

AJAX 类库的封装
JQ 中 AJAX 操作详解
$.ajax({
url:’xxx.txt’, // 请求 API 地址
method:’get’, // 请求方式 GET/POST…,在老版本 JQ 中使用的是 type,使用 type 和 method 实现的是相同的效果
dataType:’json’, //dataType 只是我们预设获取结果的类型,不会影响服务器的返回,(服务器端一般给我们返回的都是 JSON 格式的字符串),如果我们预设的是 JSON,那么类库中将把服务器返回的字符串转换为 JSON 对象,如果我们预设的是 text(默认值),我们把服务器获取的结果直接拿过来操作即可,我们预设的值还可以是 xml 等
cache:false, // 设置是否清除缓存,只对 GET 系列请求有作用,默认是 true,有缓存,手动设置为 false,无缓存,JQ 类库会在请求 URL 的末尾追加一个随机数来清除缓存
data:null, // 我们通过 data 可以把一些信息传递给服务器;GET 系列请求会把 data 中的内容拼接在 URL 的末尾通过问号传参的方式传递给服务器,POST 系列请求会把内容放在请求主体中传递给服务器。data 的值可以设置为两种格式:字符串,对象,如果是字符串,设置的值是什么传递给服务器的就是什么,如果设置的是对象,JQ 会把对象变为 xxx=xxx&xxx=xxx 这样的字符串传递给服务器
async:true,// 设置同步或者异步,默认是 true 代表异步,false 是同步
success:function(result){
// 当 AJAX 请求成功(readyState===4 & status 是以 2 或者 4 开头的)
// 请求成功后 JQ 会把传递的回调函数执行,并且把获取的结果当做实参传递给回调函数(result 就是我们从服务器获取的结果)
},
error:function(msg){}, // 请求错误触发回调函数
complete:function(){}, // 不论请求是错误的还是正确的都会触发回调函数(他是完成的意思)
})

封装属于自己的 AJAX 类库
【支持的参数】
urlmethod/type
data
dataType
async
cache
success

~ function() {
class ajaxClass {
// SEND AJAX
init() {
// THIS:EXAMPLE
let xhr = new XMLsHttpRequest();
xhr.onreadystatechange = () => {
if (!/[23]\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 4) {
let result = xhr.responseText;
// DATA-TYPE
switch (this.dataType.toUpperCase()) {
case ‘TEXT’:
case ‘HTML’:
break;
case ‘JSON’:
result = JSON.parse(result);
break;
case ‘XML’:
result = xhr.responseXML;
}
this.success(result);
};
};

// DATA
if (this.data != null) {
this.formatData();
if (this.isGET) {
this.url += this.querySymbol() + this.data;
this.data = null;
}
}

// CACHE
this.isGET ? this.cacheFn() : null;

xhr.open(this.method, this.url, this.async);
xhr.send(this.data);
}
// 把传递的对象格式 data 转换为字符串格式的 data
formatData() {
// THIS:EXAMPLE
if (Object.prototype.toString.call(this.data) === ‘[object Object]’) {
let obj = this.data,
str = “;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
str += `${key}=${obj[key]}&`;
}
}
str = str.replace(/&$/g, ”);
this.data = str;
}
}

cacheFn() {
// THIS:EXAMPLE
!this.cache ? this.url += `${this.querySymbol()}_=${Math.random()}` : null;

}

querySymbol() {
// THIS:EXAMPLE
return this.querySymbol.indexof(‘?’) > -1 ? ‘&’ : ‘?’;
}
}

// init parameters
window.ajax = function({
url = null,
method = ‘GET’,
type = ‘null’,
data = null,
dataType = ‘JSON’,
cache = true,
async = true,
success = null
} = {}) {
let example = new ajaxClass();
example.url = url;
example.method = type === null ? method : type;
example.data = data;
example.dataType = dataType;
example.cache = cache;
example.async = async;
example.success = typeof success === ‘function’ ? success : new Function();
example.isGET = /^(GET|DELETE|HEAD)$/i.test(example.method);
example.init();
return example;
};
}();
ajax({});

优化代码:
~ function() {
class ajaxClass {
// SEND AJAX
init() {
// THIS:EXAMPLE
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (!/[23]\d{2}$/.test(xhr.status)) return;
if (xhr.readyState === 4) {
let result = xhr.responseText;
// DATA-TYPE
try {
switch (this.dataType.toUpperCase()) {
case ‘TEXT’:
case ‘HTML’:
break;
case ‘JSON’:
result = JSON.parse(result);
break;
case ‘XML’:
result = xhr.responseXML;
}
} catch (e) {

}

this.success(result);
};
};

// DATA
if (this.data != null) {
this.formatData();
if (this.isGET) {
this.url += this.querySymbol() + this.data;
this.data = null;
}
}

// CACHE
this.isGET ? this.cacheFn() : null;

xhr.open(this.method, this.url, this.async);
xhr.send(this.data);
}
// 把传递的对象格式 data 转换为字符串格式的 data
formatData() {
// THIS:EXAMPLE
if (Object.prototype.toString.call(this.data) === ‘[object Object]’) {
let obj = this.data,
str = “;
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
str += `${key}=${obj[key]}&`;
}
}
str = str.replace(/&$/g, ”);
this.data = str;
}
}

cacheFn() {
// THIS:EXAMPLE
!this.cache ? this.url += `${this.querySymbol()}_=${Math.random()}` : null;

}

querySymbol() {
// THIS:EXAMPLE
return this.querySymbol.indexof(‘?’) > -1 ? ‘&’ : ‘?’;
}
}

// init parameters
window.ajax = function({
url = null,
method = ‘GET’,
type = ‘null’,
data = null,
dataType = ‘JSON’,
cache = true,
async = true,
success = 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.success = typeof success === ‘function’ ? success : new Function();
return;
}
_this[item] = eval(item);
});

_this.isGET = /^(GET|DELETE|HEAD)$/i.test(_this.method);
_this.init();
return _this;
};
}();
ajax({});

退出移动版