封装ajax
之前我们向服务器请求数据的时候,每次请求都是单一的,也就是如果要发起第二次请求、第三次请求,都会重新创建ajax,配置数据,发起请求,接受响应,这些部分很多都是一样的,就会显得代码很臃肿、繁琐,为了解决这些问题,我们可以将ajax请求封装成一个函数,如果要做项目或者再次发起请求的时候,就可以直接调用这个函数。
下面是完整版的ajax封装的代码,包括了html、JavaScript部分,每一句代码的解释都写在了里面。
运行结果可以自己将代码复制到自己的编译器中运行。
这是html部分
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
// 我们将函数封装在了一个叫做utils.js的文件里
<script src="./utils.js"></script>
</body>
</html>
这是JS文件
// 将对象转化为字符串类型
// 封装成一个函数
// 形参为要转化的对象 obj = _options.data
function objToStr(obj) {
// 定义一个空字符串存储转化后的字符串
let str = '';
// 循环遍历对象的没有个键值
for (let k in obj) {
// console.log(k , obj[k]);
// 拼接键值对
str += `${k}=${obj[k]}&`;
}
// 循环完过后 删除最后一个&
str = str.slice(0, str.length - 1);
// console.log(str);
// 一定要返回str
return str;
}
// 封装一个闭包函数
// 每次发送请求的时候url地址前面那一串都是一样的 我们可以通过闭包给这部分基地址给存一下
// 那么 这也是优化代码的一部分
function urlfun(url) {
let baceurl = url;
// 封装ajax函数
// 将所有要请求的数据以对象的形式作为形参
function ajax(options) {
// 判断数据是否传入正确
// url地址必须传递 不允许为空(undefined) 如果为空 就扔出报错信息
if (options.url === undefined) throw new Error('您没有传递url地址 或者 没有正确传递url地址');
// method请求方式必须传递 只能为get 或者 post 也可能没有传递(undefined) 没有传递的话 就传递默认值
// 如果不满足条件 就扔出报错信息
// 这里可以使用正则来判断是否为get或post 他们不区分大小写
if (!(options.method === undefined || /^(get|post)$/i.test(options.method))) throw new Error(
'请求方式只能为get或者post');
// asyrc同步异步 默认值为异步程序true 也可以没有传递(undefined) 如果不满足条件 就扔出报错信息 只能为true和false
// 可以使用数据类型判断typeof来进行判断 是否为布尔值
if (!(typeof options.async === 'boolean' || options.async === undefined)) throw new Error('同步异步只能是ture和false');
// data数据类型可以是字符串 但是只能是字符串的形式传递 也可能没有传递data 就是undefined
// 如果要传入的数据很多的时候 用字符串的方式就很麻烦 那么我们为方便 可以以键值对的形式存储在对象中
// 所以 data可以是 字符串 可以是对象 可以是undefined 如果不满足条件 就扔出报错信息
// 判断字符串 对象 undefined类型 使用实际项目中使用的方法
// object.prototype.toString.call();
// console.log(Object.prototype.toString.call(options.data));
const dataTypeJudge = Object.prototype.toString.call(options.data);
if (!(dataTypeJudge === '[object Object]' || dataTypeJudge === '[object String]' || dataTypeJudge ===
'[object Undefined]')) {
throw new Error('数据类型只能是字符串或者对象');
}
// 请求头只能是对象的形式 或者undefined 如果不满足条件就弹出报错信息
const HeaderTypeJudge = Object.prototype.toString.call(options.headers);
if (!(HeaderTypeJudge === '[object Undefined]' || HeaderTypeJudge === '[object Object]')) {
throw new Error('数据类型只能是对象');
}
// 数据类型只能是字符串和json类型
// 使用正则来判断是否为正确
if (!(options.dataType === undefined || /^(string|json)$/.test(options.dataType))) {
throw new Error('数据类型只能是字符串类型或者json类型');
}
// 默认参数设定
// 当我们没有传入参数的形式 就要设定默认参数
const _options = {
url: baceurl + options.url,
// 如果method没有传入 就设定默认值为get
method: options.method || 'get',
// 如果async同步异步没有传入 就设定默认值为true
// 如果options.async为false的时候 那么就会默认执行true
// 所以这里要用到控制运算符 ??
// 当前面一个数值为undefined或者null 就会默认执行后面一个设定的默认值
async: options.async ?? true,
// data为对象的形式 要将其转化为字符串类型 默认值为没有传入
data: options.data || '',
// 设定请求头 运用展开运算符获取所有的数据
headers: {
'content-type': 'application/x-www-form-urlencoded',
...options.headers,
},
// 配置默认值为字符串类型
dataType: options.dataType || 'string',
}
// 如果数据类型为对象就调用 objToStr 函数
if (typeof _options.data === 'object') _options.data = objToStr(_options.data);
// 如果请求方式为get 配置传输数据方式
// 使用正则的方式判断get 不区分大小写
if (/^(get)$/i.test(_options.method)) _options.url = _options.url + '?' + _options.data;
// 执行后续代码
// console.log('执行请求');
// 发送ajax请求
// 通过promise来实现异步请求 并且在响应请求的时候 如果请求成功 通过调用then语法返回成功执行的代码 通过res来调用
// promise有两个默认要传入的两个参数 一个是执行程序成功需要调用的回调函数fullfilled 一个是执行程序失败需要调用的程序
const p = new Promise(function(fullfilled, rejected) {
// 创建ajax请求
const xhr = new XMLHttpRequest();
// 配置参数
xhr.open(_options.method, _options.url, _options.async);
// 为了防止同步false的时候出现错误 我们就先接收响应 在发送请求
xhr.onload = function() {
// console.log(xhr.responseText);
// 使用的promise执行异步代码 可以通过then方法返回成功状态
// fullfilled(xhr.responseText);
// 判断是否为json还是string 再根据判断写入响应的文本
// if (_options.dataType === 'string') {
// // 就直接传入
// fullfilled(xhr.responseText);
// } else {
// fullfilled(JSON.parse(xhr.responseText));
// }
// 对上面这一步做一个小的优化
try {
if (_options.dataType === 'string') {
fullfilled({
code: 1,
info: xhr.responseText,
})
} else {
fullfilled({
code: 1,
info: JSON.parse(xhr.responseText),
})
}
} catch {
fullfilled({
code: 0,
info: xhr.responseText,
})
}
}
// 发送请求
// xhr.send();
// 设定请求头
// 当请求方式为post的时候 需要设定请求头
if (/^(post)$/i.test(_options.method)) xhr.setRequestHeader('content-type', _options.headers[
'content-type']);
// 还有一个做认证的请求方式 需要设定 token参数get和post都可能会需要
if (/^(get|post)$/i.test(_options.headers.authorization)) xhr.setRequestHeader('authorization',
_options.headers.authorization);
// 如果这是post请求 需要设定参数
(/^(post)$/i.test(_options.method)) ? xhr.send(_options.data): xhr.send();
})
// 封装过后 一定要将p返回 才能在函数外部使用
return p;
// 查看传入的参数 以及默认传参
console.log(options);
console.log(_options);
// 调用函数
// 输入实参
}
// 外层函数调用内容函数
return ajax;
}
// 调用函数 并传入基地址作为实参
const ajax = urlfun('http://localhost:8888');
// 测试一:
ajax({
url: '/test/first',
}).then(fullfilled => {
// console.log('promise过后的成功请求:', fullfilled);
// 通过code来判断是请求成功还是请求失败
if(fullfilled.code === 0){
console.log('请求失败:' , fullfilled);
}else{
console.log('请求成功:' , fullfilled);
}
})
// 测试二:需要转化成json字符串并传参
// 这是get请求方式 需要传递一个name参数
ajax({
// url地址可能会出现错误的情况 那么出现错的情况 而且还配置了dataType
// 就会报错 那么我们可以通过try...catch来做一个报错后的信息文本响应
url: '/test/thir1d',
method: 'get',
data: 'name=羽生&age=18',
// 每次判断数据类型的时候 都要用JSON.parse转换一下
// 所以可以传一个参数dataType作为判断
// dataType只有两种形式 一种是字符换string 一种是json类型
// 其实也就是把服务器传给我们的文本转换成我们前端认识的格式类型
dataType: 'json',
}).then(fullfilled => {
console.log('promise过后的成功请求:', fullfilled);
})
// 测试三:post请求 需要转化成json字符串 并传参
// 这是post请求方式 需要设定一个name参数 并且设置请求头
// name参数在send里面设定
ajax({
url: '/test/fourth',
method: 'post',
data: 'name=羽生&age=18',
headers: {
authorization: 'token'
},
dataType: 'json',
}).then(fullfilled => {
console.log('promise过后的成功请求:', fullfilled);
})