ajax
请求能够说是在前端开发工做中必不可少的一个东西html
一、ajax
请求原理前端
ajax
技术的核心是XMLHttpRequest
对象,其经过建立一个XMLHttpRequest
对象,利用对象的open
方法发送请求,判断对象中readyState
属性(请求、响应过程的当前活动阶段)的值和status
(Http的响应状态)的值,获得responseText
等open
方法的三个参数
URL
readyState
属性的值
open()
方法open()
方法,但还没有调用send()
方法。send()
方法,但还没有接收到响应。二、jQuery
、小程序风格的ajax
请求封装 jQuery
风格的代码样式node
$.ajax({
url: xxx,
success: () => {},
fail: err => {},
})
复制代码
由上,咱们知道在封装函数的时候,首先,它接收的是一个对象,因此,第一步:ajax
const ajax = ({}) => {}
复制代码
接下来,咱们定义对象内部须要接收的参数,有:url
(请求的地址)、data
(发送的数据)、method
(请求方式)、header
(请求头部信息)、success
(请求成功回调函数)、fail
(请求失败回调函数)、async
(请求是否异步)、timeout
(设置请求超时时间)、onTimeOut
(超时处理回调函数)、...小程序
const ajax = ({
url,
data = {},
method = 'get', // 默认为'get'请求
header,
async = true, // 默认为异步请求
timeout,
success,
fail,
}) => {}
复制代码
咱们一般会使用get
请求向服务器查询一些信息,也一般会在请求的url
后面拼接上数据,像这样:api
http://www.baidu.com?a=b&c=d...
复制代码
那咱们如何实现呢?咱们定义一个拼接url
函数,须要两个参数,一个是自己的url
,另一个是向后台发送的数据param
,因此:promise
// 数据拼接url
addURL = (url, param) => {
if(param && Object.keys(param).length) { // 数据不为空
// 判断url后添加的字符是'?'仍是'&'
url += (url.indexOf('?') === -1 ? '?' : '&');
// 拼接数据
Object.keys(param).map(key => {
url += `${key}=${param[key]}`
})
}
return url;
}
复制代码
一般呢,咱们使用get
方法会遇到查询字符串格式错误的问题,因此,这时须要咱们用encodeURIComponent()
进行编码,上面代码改变以下:浏览器
addURL = (url, param) => {
if(param && Object.keys(param).length) {
url += (url.indexOf('?') === -1 ? '?' : '&');
Object.keys(param).map(key => {
url += encodeURIComponent(key) + '=' + encodeURIComponent(param[key])
})
}
}
复制代码
若是使用的是post
方法,咱们只须要将数据给服务端传递过去,最终,咱们写出了封装后的代码:bash
const ajax = ({
url,
data = {},
method = 'get', // 默认为'get'请求
header,
async = true, // 默认为异步请求
timeout = 60 * 1000, //默认60s
success,
fail,
}) => {
const requestURL = method === 'get' ? this.addURL(url, data) : url;
const sendData = method === 'get' ? null : data;
const xhr = new XMLHttpRequest();
if(header && Object.keys(header).length) {
Object.keys(header).map(key => {
xhr.setRequestHeader(key, header[key]);
})
}
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
try {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
const response = xhr.responseText;
success(response);
} else {
const error = xhr.status + xhr.statusText;
fail(error);
}
} catch (ex) {
}
}
}
xhr.open(method, requestURL, async);
xhr.timeout = timeout;
xhr.ontimeout = () => {
console.log('timeout');
}
xhr.send(sendData);
}
// 拼接url
addURL = (url, param) => {
if(param && Object.keys(param).length) {
url += (url.indexOf('?') === -1 ? '?' : '&');
Object.keys(param).map(key => {
url += encodeURIComponent(key) + '=' + encodeURIComponent(param[key])
})
}
return url;
}
复制代码
上述代码中,利用了try-catch
语句。这是由于当请求在指定时间内没有返回,就会自动终止,请求终止后,会调用ontimeout
事件处理程序,若是readyState
已经变为4
,就会调用onreadystatechange
事件处理程序,这种状况下,会在请求终止后再次访问status
属性,就会致使浏览器报告错误,因此,为了不错误,咱们将status属性语句封装在try-catch
语句中。服务器
下面,咱们验证一下,咱们封装好的函数是否可用
// html
<button id="ajax_btn">ajax请求</button>
// js
const ajax_btn = document.getElementById('ajax_btn');
ajax_btn.onclik = () => {
ajax({
url: 'http://localhost:3001/123',
data: {},
header: {},
timeout: 20 * 1000,
success: res => {
console.log(res);
},
fail: err => {
throw err;
}
});
};
复制代码
页面样式
三、promise
风格的ajax
请求封装
promise
风格的代码
ajax.get('/api').then(res => {}).catch(err => {}).finally();
复制代码
定义封装ajax
函数须要的参数
const ajax = ({
url,
data,
method = 'get',
header,
async = true,
timeout = 60 * 1000,
}) => {};
复制代码
接下来,按照jQuery风格的思路,进行封装
const ajax = ({
url,
data = {},
method = 'get', // 默认为'get'请求
header,
async = true, // 默认为异步请求
timeout = 60 * 1000, //默认60s
}) => {
return new Promise((resolve, reject) => {
const requestURL = method === 'get' ? this.addURL(url, data) : url;
const sendData = method === 'get' ? null : data;
const xhr = new XMLHttpRequest();
if(header && Object.keys(header).length) {
Object.keys(header).map(key => {
xhr.setRequestHeader(key, header[key]);
})
}
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
try {
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
const response = xhr.responseText;
resolve(response);
} else {
const error = xhr.status + xhr.statusText;
reject(error);
}
} catch (ex) {
//
}
}
}
xhr.open(method, requestURL, async);
xhr.timeout = timeout;
xhr.ontimeout = () => {
console.log('timeout');
}
xhr.send(sendData);
})
}
// 拼接url
addURL = (url, param) => {
if(param && Object.keys(param).length) {
url += (url.indexOf('?') === -1 ? '?' : '&');
Object.keys(param).map(key => {
url += encodeURIComponent(key) + '=' + encodeURIComponent(param[key])
})
}
return url;
}
// get请求
ajax.get = (url, data) => {
return ajax({
url,
data,
})
}
// post请求
ajax.post = (url, data) => {
return ajax({
url,
data,
method = 'post',
})
}
复制代码
下面,咱们验证一下封装好的promise
风格的ajax
函数的可用性
// html
<button id="ajax_btn">ajax请求</button>
// js
const ajax_btn = document.getElementById('ajax_btn');
ajax_btn.onclick = () => {
ajax.get('http://localhost:3001/test')
.then(res => {
console.log(res);
})
.catch(err => {
throw err;
})
.finally(console.log('finally'))
}
复制代码
点击按钮
get
请求换成
post
请求
promise
风格的
ajax
请求函数
四、优化
在IE
中,XHR对象是经过MSXML
库中的ActiveX
对象实现的。因此,在IE
中,可能会有三种不一样版本的XHR
对象(MSXML2.XMLHttp
、MSXML2.XMLHttp.3.0
、MSXML2.XMLHttp.6.0
),若是咱们要使用库中的XHR
对象,就须要编写一个函数(只适用于IE7
之前的版本)
function createXHR() {
if (typeof arguments.callee.activeXString !== 'string') {
const versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'];
for(let i = 0; i< versions.length; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
// 跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
}
复制代码
若是想要支持IE7
以上的版本,只须要在上述函数中加入对原生XHR
对象的支持,即:
function createXHR() {
if (typeof XMLHttpRequest !== 'undefined') {
return new XMLHttpRequest();
} else if(typeof ActiveXObject !== 'undefined') {
if(typeof arguments.callee.activeXString !== 'string') {
const versions = ['MSXML2.XMLHttp.6.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp'];
for(let i = 0; i< versions.length; i++) {
try {
new ActiveXObject(versions[i]);
arguments.callee.activeXString = versions[i];
break;
} catch (ex) {
// 跳过
}
}
}
return new ActiveXObject(arguments.callee.activeXString);
} else {
throw new Error('no XHR object available');
}
}
复制代码
经过这样的方式,咱们能够直接建立XHR
对象:
const xhr = new createXHR();
复制代码
效果: