一、封装分析
(一 )封装方案
1、回调函数方式
将来使用的时候, 可能会遇到
回调地狱
2、promise方式
效果不会有变化, 而且还能和
async/await
一起使用
(二)函数的参数
- 请求方式:
method
=> 默认值 get- 请求地址:
url
=> 必填- 同步异步:
async
=> 默认值 true- 请求参数:
data
=> 默认值 ‘’- 请求头:
headers
=> 默认值 {content-type: application/x-www-form-urlencoded}- 解析参数:
dataType
=> 默认值 ‘string’
注意:将以上参数封装成对象(options)
的形式更加方便
(三)函数的返回值
- promise
实例化对象
- 让开发自己使用
.then或者 .catch
二、参数的验证
function ajax(options) {
// 请求地址: url => 必填,也就是说url不能为undefined
if (options.url === undefined) {
throw new Error('您没有传递url,url为必填')
}
// 请求方式: method => 默认值get
// 也就是说method可以是get、post和undefined
if (!(/^(get|post)$/i.test(options.method) || options.method === undefined)) {
throw new Error('method目前仅支持post或者get')
}
// 同步异步: async => 默认值true
// 也就是说 async可以为true,false和undefined
if (!(options.async === undefined || typeof (options.async) === 'boolean')) {
throw new Error('async目前仅支持true或false')
}
// 请求参数: data => 默认值 ''
// 参数data可以是字符串、对象和undefined
const optionsDataType = Object.prototype.toString.call('options.data');
if (!(
optionsDataType === "[object Object]" ||
optionsDataType === "[object String]" ||
optionsDataType === "[object Undefined]"
)) throw new Error('data目前仅支持字符或对象')
// 请求头: headers => 默认值 {content-type: application/x-www-form-urlencoded}
// headers可以时候undefined,也可以是对象
const headersType = Object.prototype.toString.call(options.headers)
if(!(headersType === '[object Undefined]' || headersType === '[object Object]')){
throw new Error('headers暂时仅支持对象格式')
}
// 解析参数: dataType => 默认值 'string'
// dataType参数可以是undefined、'string'和'json'
if(options.dataType === undefined || /^(string|json)$/.test(options.dataType)){
throw new Error('dataType目前净资产string和JSON')
}
console.log(options);
}
ajax({
url: 'http://localhost:8888',
data: 'key=value',
method: 'get',
async: true,
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
dataType: ''
})
验证:当我们不传url时
ajax({
data: 'key=value',
method: 'get',
async: true,
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
dataType: ''
})
三、处理默认参数
1、补充知识点
- ??:
空值运算符
- 作用:符号左边是
undefined或者null
,会运行符号右边
的
2、封装函数处理data对象
function objToStr(obj){
let str = '';
for(let key in obj){
str += `${key}=${obj[key]}&`;
}
str = str.slice(0, str.length-1);
return str;
}
3、结构解析
let obj1 = {
a: 1,
b: 2
}
let obj2 ={
c: 3,
d: 4,
...obj1
}
console.log(obj2);
4、处理默认参数
继续在ajax函数里面书写
// 默认传输的处理
const _options = {
// 代码执行到这个位置 说明url一定传递了
url: options.url,
// 代码运行到这里,method要么是undefined,要么是get/post
method: options.method || 'get',
// ??空值运算符 符号左边是undefined或者null,会运行符号右边的
async: options.async ?? true,
// 代码运行到这里,data可能是对象、字符串和undefined
data: options.data || '',
// 代码运行这里 headers可能是undefined或对象
headers: {
"content-type": "application/x-www-form-urlencoded",
...options.headers,
},
// 代码运行到这里 dataType可能是undefined或者字符串
dataType: options.dataType || 'string',
}
// 处理_options.data中对象转化为模板字符串
if (!(typeof (_options.data) === 'string')) {
// console.log(_options.data);
_options.data = objToStr(_options.data)
}
console.log('原始对象', options);
console.log('默认数据', _options);
四、设置get和post请求头
GET请求
:不需要content-type,可能需要authorizationPOST请求
:需要content-type,可能需要authorization
// 如果当前是get请求 在路径后拼接参数
if (/^grt$/i.test(_options.method)) {
_options.url = options.url + '?' + _options.data
}
// 发送请求
const p = new Promise((res, rej) => {
const xhr = new XMLHttpRequest();
xhr.open(_options.method, _options.url, _options.async);
xhr.onload = function () {
// 代码运行到这里 dataType要么是string,要么是JSON
if (_options.dataType === 'string') {
res(xhr.responseText);
} else {
res(JSON.parse(xhr.responseText))
}
};
// 对post请求认证的处理
if (/^post$/i.test(_options.method)) {
xhr.setRequestHeader('content-type', _options.headers["content-type"])
}
if (_options.headers.authorization) {
xhr.setRequestHeader('authorization', _options.headers.authorization)
}
// 如果当前是post请求,那么send内部需要添加参数 否则不需要
/^POST$/i.test(_options.method) ? xhr.send(_options.data) : xhr.send();
})
return p;
五、完整代码
function createAjax(url){
let baseUrl = url;
function ajax(options) {
// 请求地址: url => 必填,也就是说url不能为undefined
if (options.url === undefined) {
throw new Error('您没有传递url,url为必填')
}
// 请求方式: method => 默认值get
// 也就是说method可以是get、post和undefined
if (!(/^(get|post)$/i.test(options.method) || options.method === undefined)) {
throw new Error('method目前仅支持post或者get')
}
// 同步异步: async => 默认值true
// 也就是说 async可以为true,false和undefined
if (!(options.async === undefined || typeof (options.async) === 'boolean')) {
throw new Error('async目前仅支持true或false')
}
// 请求参数: data => 默认值 ''
// 参数data可以是字符串、对象和undefined
const optionsDataType = Object.prototype.toString.call('options.data');
if (!(
optionsDataType === "[object Object]" ||
optionsDataType === "[object String]" ||
optionsDataType === "[object Undefined]"
)) throw new Error('data目前仅支持字符或对象')
// 请求头: headers => 默认值 {content-type: application/x-www-form-urlencoded}
// headers可以时候undefined,也可以是对象
const headersType = Object.prototype.toString.call(options.headers)
if (!(headersType === '[object Undefined]' || headersType === '[object Object]')) {
throw new Error('headers暂时仅支持对象格式')
}
// 解析参数: dataType => 默认值 'string'
// dataType参数可以是undefined、'string'和'json'
if (!(options.dataType === undefined || /^(string|json)$/.test(options.dataType))) {
throw new Error('dataType目前仅支持string和JSON')
}
// 默认传输的处理
const _options = {
// 代码执行到这个位置 说明url一定传递了
url: baseUrl + options.url,
// 代码运行到这里,method要么是undefined,要么是get/post
method: options.method || 'get',
// ??空值运算符 符号左边是undefined或者null,会运行符号右边的
async: options.async ?? true,
// 代码运行到这里,data可能是对象、字符串和undefined
data: options.data || '',
// 代码运行这里 headers可能是undefined或对象
headers: {
"content-type": "application/x-www-form-urlencoded",
...options.headers,
},
// 代码运行到这里 dataType可能是undefined或者字符串
dataType: options.dataType || 'string',
}
// 处理_options.data中对象转化为模板字符串
if (!(typeof (_options.data) === 'string')) {
// console.log(_options.data);
_options.data = objToStr(_options.data)
}
// 如果当前是get请求 在路径后拼接参数
if (/^grt$/i.test(_options.method)) {
_options.url = options.url + '?' + _options.data
}
// 发送请求
const p = new Promise((res, rej) => {
const xhr = new XMLHttpRequest();
xhr.open(_options.method, _options.url, _options.async);
xhr.onload = function () {
// 代码运行到这里 dataType要么是string,要么是JSON
if (_options.dataType === 'string') {
res(xhr.responseText);
} else {
res(JSON.parse(xhr.responseText))
}
};
// 对post请求认证的处理
if (/^post$/i.test(_options.method)) {
xhr.setRequestHeader('content-type', _options.headers["content-type"])
}
if (_options.headers.authorization) {
xhr.setRequestHeader('authorization', _options.headers.authorization)
}
// 如果当前是post请求,那么send内部需要添加参数 否则不需要
/^post$/i.test(_options.method) ? xhr.send(_options.data) : xhr.send();
})
return p;
}
return ajax;
}
function objToStr(obj) {
let str = '';
for (let key in obj) {
str += `${key}=${obj[key]}&`;
}
str = str.slice(0, str.length - 1);
return str;
}
// 基址:闭包实现
const ajax = createAjax("http://localhost:8888");
const ajax1 = createAjax("http://localhost:8080");