ajax的两种方式,封装ajax请求的两种方式

2023-05-16

ajax请求可以说是在前端开发工作中必不可少的一个东西

1、ajax请求原理

ajax技术的核心是XMLHttpRequest对象,其通过创建一个XMLHttpRequest对象,利用对象的open方法发送请求,判断对象中readyState属性(请求、响应过程的当前活动阶段)的值和status(Http的响应状态)的值,得到responseText等

open方法的三个参数

第一个参数:请求方式

第二个参数:请求的URL

第三个参数:是否异步(大多数使用异步请求)

readyState属性的值

0:未初始化。尚未调用open()方法

1:启动。已经调用open()方法,但尚未调用send()方法。

2:发送。已经调用send()方法,但尚未接收到响应。

3:接收。已经接收到部分响应数据。

4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。

status属性的值

成功:(>= 200 && < 300) || === 304

失败:除去成功的情况

2、jQuery、小程序风格的ajax请求封装

jQuery风格的代码样式

$.ajax({

url: xxx,

success: () => {},

fail: err => {},

})

复制代码

由上,我们知道在封装函数的时候,首先,它接收的是一个对象,所以,第一步:

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后面拼接上数据,像这样:

http://www.baidu.com?a=b&c=d...

复制代码

那我们如何实现呢?我们定义一个拼接url函数,需要两个参数,一个是本身的url,另外一个是向后台发送的数据param,所以:

// 数据拼接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方法,我们只需要将数据给服务端传递过去,最终,我们写出了封装后的代码:

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

ajax请求

// 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;

}

});

};

复制代码

页面样式

00ed47161377f594b79a4dc74c0ffb26.png

点击按钮,就会发送请求,接下来,是见证奇迹的时刻:

15ad7b8e151f8dd885b20065189a2179.png

e8fbfdc0dd2063dada0e01ec3c921cd6.png

我们成功获得了服务端返回的数据(服务端是自己用node写的一个极其简易的接口)

3、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

ajax请求

// 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'))

}

复制代码

点击按钮

1dca2b25b2eeeca8a1da199191799992.png

1dc0e966ddc84263dae1b7bd258d26fa.png

当我们将get请求换成post请求

28dedd0e28b2f1f5a6741b0866ae8507.png

c0fd5c9898b282daf21048c8780369f6.png

至此,我们成功地封装了promise风格的ajax请求函数

4、优化

在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();

复制代码

效果:

0e6d435db2c316eb118d392aedfadc82.png

797a45aa50d22d48502993c6597d12b0.png

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ajax的两种方式,封装ajax请求的两种方式 的相关文章

随机推荐