一、用到小知识点
?? 空值运算 , 只要这个符号前面不为空 , 就是使用 , 如果前面为空了就使用后面的
二、封装
需要考虑以下几点
1、封装方案
若使用回调函数不利于我们代码的维护与阅读,我们可以利用Promise的形式进行封装
2、参数的默认值,不同的请求需要传递不同的参数
-
请求地址(url):没有默认值
-
请求方式(method),有默认值 , 默认发送 get
-
是否异步(async):有默认值 , 默认值是 true
-
传递参数(data): 有默认值 , 默认值就是 ''(空字符串)
-
需要设置请求头信息(headers):有默认值 , 以对象的方式来传递 默认值:{ content-type :'application/x-www-form-urlencoded'}
-
是否解析响应体(dataType):有默认值 , 默认值'string'
3、需不需要有返回值
按照 Promise 进行封装,需要一个返回值 , 这个返回值是 Promise 对象,将来我们使用的时候就可以在then或者是catch里面接收结果了
4、参数的设计(我们在封装的时候需要如何来安排我们的参数)
-
参数的位置 , 和我们参数的数量
-
我们将来在传递的时候需要好传递(方便我们传递)
-
我们在封装的时候还要好接收这个参数
-
我们参数的传递以对象的方式传递
-
封装的时候 , 也是通过对象的方式来拿
function parseQueryString(obj) {
var str = ''
for (var k in obj) {
str += k + '=' + obj[k] + '&'
}
str = str.slice(0, -1)
return str
}
// let res = parseQueryString({ name: 'Rose', age: 20 })
// console.log(res);
// 查询字符串: key=value&key1=value1&key2=value2
// 这里是我们的封装的过程
function ajax(options = {}) {
// console.log(options);
// 首先需要拿到传递进来的参数
const { url, method, async, data, headers, dataType} = options;
// 就是需要对我们传递进来的参数进行验证了
// 1. 验证我们的每一个参数
// 验证 url
if (!url || typeof url !== 'string') throw new Error('url必须传递 而且是一个字符串,格式不对')
// 验证 method
if (!(method === undefined || /^(get|post)$/i.test(method))) throw new Error('你传递到的请求方式不正确 , 核对后再试')
// 验证 async
if (!(async === undefined || typeof async === 'boolean')) throw new Error('这里需要的是一个布尔数据类型, 你传递的不正确')
// 验证 data
// 这里也可以传递一个对象 , 我在这里给你转成查询字符串
if (!(data === undefined || typeof data === 'string' || Object.prototype.toString.call(data) === '[object Object]')) {
throw new Error('这里必须是一个字符串数据类型或者是对象数据类型 , 你传递的不正确')
}
// 验证headers
if (!(headers === undefined || Object.prototype.toString.call(headers) === '[object Object]')) {
throw new Error('这里我们需要的是一个对象数据类型 , 你传递的不正确')
}
// 验证 dataType
if (!(dataType === undefined || /^(string|json)$/i.test(dataType))) throw new Error('dataType只能是一个string或者是json')
// 2. 设置一套默认值
const _default = {
// url 没有默认值 , 你传递什么我使用什么
url: url,
// method 如果你传递了使用你传递的 , 没有传递的时候我们使用的是默认值
method: method || 'GET',
// async 如果你传递了使用你传递的 , 没有传递的时候我们使用的是默认值
async : typeof async === 'boolean' ? async : true,
// async : async ?? true // ?? 空值运算 , 只要这个符号前面不为空 , 就是使用 , 如果前面为空了就使用后面的
// data 如果你传递了使用你传递的 , 没有传递的时候我们使用的是默认值
data: data || '',
// headers 如果你传递了使用你传递的 , 没有传递的时候我们使用的是默认值
headers: { 'content-type': 'application/x-www-form-urlencoded', ...headers },
// dataType 如果你传递了使用你传递的 , 没有传递的时候我们使用的是默认值
dataType: dataType || 'string'
}
// 2-1 默认值的操作
// 如果你携带的参数是以对象的方式携带的
// 就需要把对象转成查询字符串
// 首先要确定你传递进来的一定是一个对象
if (typeof _default.data === 'object') {
// 代码能执行到这里 , 说明一定是一个对象
// 需要把对象转成查询字符串
_default.data = parseQueryString(data)
}
// 2-2 . 如果你是get请求 , 并且携带了参数 , 这个时候我们就可以给你拼接好了
if (/^get$/i.test(_default.method) && _default.data) {
// 代码能执行到这里 , 说明是get请求 并且携带了参数
_default.url = _default.url + '?' +_default.data
}
// 3. 发送请求
// 我们一开始就决定了要使用Promise的形式进行封装
const p = new Promise(function (resolve, reject) {
// 创建ajax对象
const xhr = new XMLHttpRequest()
// 配置请求信息
xhr.open(_default.method, _default.url, _default.async)
// 注册一个响应函数
xhr.onload = function () {
// let res = xhr.responseText
//如果是 string 直接把这个结果给你返回就好了
// 如果是 json 我们就需要帮你解析完了以后再给你
if (_default.dataType === 'string') {
// 代码能执行到这里 , 说明后端返回的是就是一个普通字符串
// resolve(xhr.responseText)
resolve({code:1, message:'成功',info:xhr.responseText})
} else {
// 后端返回的是不是一个普通字符串 , 就是JSON格式字符串
// 需要我们做的是容错处理
try {
let res = JSON.parse(xhr.responseText)
resolve({code:1, message:'成功',info: res})
} catch (err) {
resolve({code:0, message:'失败',info: err})
}
}
}
// 如果是post请求 , 还要设置一个请求头
// 因为是一个对象 ,我们要从对象中拿到我们需要的内容
// 循环遍历我们的对象了
for (let k in _default.headers) {
xhr.setRequestHeader(k,_default.headers[k])
}
// 如果是get请求 , 可以直接发送
// 如果是post请求 ,有参数 我们需要在请求体中携带参数
if (/^get$/i.test(_default.method)) {
xhr.send()
} else {
xhr.send(_default.data)
}
})
// 最后我们是不是要返回这个Promise对象
return p
}
// 将来使用
// let res = ajax({
// url: 'http://localhost:8888/test/fourth',
// method: 'post',
// // async: false,
// // 可以以对象的方式进行传递
// // data: 'name=Rose&age=30',
// data: {
// name: 'Tom',
// age:50
// },
// // headers: {},
// dataType: 'json',
// })
// res.then(r => console.log(r.info.info))