参数:
1. 请求地址(url)
2. 请求方式(method)
3. 是否异步(async)
4. 携带给后端的参数(data)
5. 是否存在 token(token)
6. 是否对响应体进行解析(dataType)
7. 请求成功后执行的函数(success)
参数是否有默认值:
1. url: 没有, 必填
2. method: 可以有, GET
3. async: 可以有, 默认 true, 选填是 false 表示非异步
4. data: 可以有, ''
5. token: 可以有, ''
6. dataType: 可以有, 'string' 表示不执行 JSON.parse(), 选填 'json' 表示执行 JSON.parse()
7. success: 可以有, 默认是一个空函数
对你传递的参数进行验证
1-1. 验证你的 options 内 url 必填
=> 如果你没有 url, 不需要继续执行代码了
1-2. 验证你的 options 内的 method 填写
=> 可以不传递, 只要你传递了, 必须是 GET 或者 POST
1-3. 验证你的 options 内的 async 填写
=> 可以不传递, 只要你传递了, 必须是 true 或者 false
1-4. 验证你的 options 内的 data 填写
=> 可以不传递, 只要你传递了, 必须是 字符串 类型
1-5. 验证你的 options 内的 token 填写
=> 可以不传递, 只要你传递了, 必须是 字符串 类型
1-6. 验证你的 options 内的 dataType 填写
=> 可以不传递, 只要你传递了, 必须是 'string' 或者 'json'
1-7. 验证你的 options 内的 success 填写
=> 可以不传递, 只要你传递了, 必须是一个 function 类型
function ajax(options = {}) {
// options 就是你传递进来的所有对于本次请求的配置信息
// console.log('你传递进来的数据 : ', options)
// 1. 参数验证
// 1-1. 验证 options.url
if (!options.url) {
// 表示 url 是 undefined 或者 null 或者 '' 或者 0
// 手动抛出异常
// 语法: throw new Error('报错信息')
// 作用: 直接在控制台报错, 阻断程序的继续执行
throw new Error('url 为必填选项, 请填写 ^_^')
}
// 1-2. 验证 options.method
// 可以是 undefined, 可以是 'GET', 可以是 'POST'
if (!(options.method === undefined || /^(get|post)$/i.test(options.method))) {
// 代码能执行到这里, 说明你的 method 不是 undefined 不是 get 不是 post
throw new Error('目前版本只接受 GET 和 POST 请求, 请期待更新 !! (#^.^#)')
}
// 1-3. 验证 options.async
// 可以是 undefined, 可以是 布尔值
if (!(options.async === undefined || typeof options.async === 'boolean')) {
throw new Error('async 只能传递 布尔值, 请检查后操作')
}
// 1-4. 验证 options.data
if (!(options.data === undefined || typeof options.data === 'string')) {
throw new Error('data 需要传递一个 字符串 格式')
}
// 1-5. 验证 options.token
if (!(options.token === undefined || typeof options.token === 'string')) {
throw new Error('token 需要传递一个 字符串 格式')
}
// 1-6. 验证 options.dataType
if (!(options.dataType === undefined || /^(string|json)$/i.test(options.dataType))) {
throw new Error('dataType 只能传递 "string" 或者 "json"')
}
// 1-7. 验证 options.success
if (!(options.success === undefined || typeof options.success === 'function')) {
throw new Error('success 需要传递一个 function 类型的数据')
}
// 2. 设置一套默认值
const _default = {
// 代码能执行到这里, 说明 url 必须有值
url: options.url,
// 代码能来到这里, 说明 method 要么是 undefined, 要么是 GET, 要么是 POST
method: options.method || 'GET',
// 代码能来到这里, 说明 async 要么是 undefined, 要么是 true 要么是 false
async: typeof options.async === 'boolean' ? options.async : true,
// async: options.async ?? true
// 代码能来到这里, 说明 data 要么是 undefined, 要么是 字符串
data: options.data || '',
// 代码能来到这里, 说明 token 要么是 undefined, 要么是 字符串
token: options.token || '',
// 代码能来到这里, 说明 dataType 要么是 undefined, 要么是 string 或者 json
dataType: options.dataType || 'string',
// 代码能来到这里, 说明 success 要么是 undefined, 要么是一个 函数
success: options.success || function () {},
error: options.error || function () {}
}
// 2-2. 判断一下, 如果是 GET 请求, 并且 data 有内容
// 那么我们直接把 data 拼接到 url 的后面
if (_default.method.toUpperCase() === 'GET' && _default.data) {
// 代码能来到这里, 说明 是 GET 请求, 并且 data 有内容
_default.url += '?' + _default.data
}
// 3. 按照 _default 内的内容发送请求
// 3-1. 创建 ajax 对象
const xhr = new XMLHttpRequest()
// 3-2. 配置请求信息
xhr.open(_default.method, _default.url, _default.async)
// 3-3. 接受响应
xhr.onload = function () {
// 判断一下, 如果 dataType 是 'string' 那么我就不执行 JSON.parse()
// 如果你的 dataType 是 'json' 那么我就执行一下 JSON.parse()
const result = _default.dataType.toUpperCase() === 'JSON' ? JSON.parse(xhr.responseText) : xhr.responseText
// 请求完成, 只要调用 success 函数就可以了
_default.success(result)
}
// 3-4. 是否填写 token 作为请求头内的一个信息
if (_default.token) xhr.setRequestHeader('authorization', _default.token)
// 3-5. 如果是 POST 请求, 设置一下请求头的格式
if (_default.method.toUpperCase() === 'POST') xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// 3-6. 发送请求
// 如果是 GET 请求, 直接书写 xhr.send()
// 如果是 POST 请求你, 书写 xhr.send(参数)
_default.method.toUpperCase() === 'POST' ? xhr.send(_default.data) : xhr.send()
}
// 本页面需要获取个人信息
// 刚好个人信息需要 token 验证
// 请求一下 个人 信息
ajax({
url: 'http://localhost:8888/users/info',
data: `id=${ id }`,
dataType: 'json',
token: token,
success: function (res) {
// 判断登录状态是过期的
if (res.code !== 1) {
// 向 localStorage 内存储一个叫做 url 的键, 值对应的是 'rpwd' 字符串
window.localStorage.setItem('url', 'rpwd')
window.location.href = './login.html'
return
}
}
})
二次封装
//在基础的一次ajax后接着写
// 对 ajax 进行 二次封装
function pAjax(options = {}) {
const p = new Promise((resolve, reject) => {
// 执行 ajax
ajax({
url: options.url,
data: options.data,
token: options.token,
async: options.async,
method: options.method,
dataType: options.dataType,
success: function (res) {
resolve(res)
}
})
})
// 把我的 promise 对象返回出去
return p
}
// 此时的全局变量 a 和 pAjax 内的 局部变量 p 是一模一样的东西
// const a = pAjax({ url: '/xxx', data: 'xxx', dataType: 'xxxx' })
// a.then(res => {})
/*
需求:
1. 发送请求到 /test/first
2. 发送请求到 /test/second
=> 前提: 必须要等到第一个请求结束以后再次发送
3. 发送请求到 /test/third
=> 前提: 必须要等到第二个请求结束以后再次发送
*/
// 使用我按照 promise 形式封装的 pAjax 函数来完成
pAjax({ url: 'http://localhost:8888/test/first' })
.then(res => {
console.log('第一个请求结束了')
console.log(res)
// return 一个新的 promise 对象
return pAjax({
url: 'http://localhost:8888/test/second',
dataType: 'json'
})
})
.then(res => {
console.log('第二个请求结果')
console.log(res)
// return 一个新的 promise 对象
return pAjax({
url: 'http://localhost:8888/test/third',
data: 'name=Jack&age=20',
dataType: 'json'
})
})
.then(res => {
console.log('第三次请求的结果')
console.log(res)
})