导言
在最先之前先想一想ajax是如何的流程
- 起首翻开一个衔接
- 发送数据
- 返回效果
我们要自定义的设置有哪些
- 设置要求体式格局
- 设置要求头
- 设置返回数据花样
- 返回胜利后或失利后
我们要做的功用有哪些
- 数据校验
- 一致数据的花样
- 支撑文件上传
- 关于传入参数的容错处置惩罚
- 超时处置惩罚 //modify time 2019-01-01
经由以上思索基础构造大抵成型
- 数据校验
- 数据花样的一致
- 竖立衔接
- 设置要求头
- 设置返回数据花样
- 发送数据
- 返回胜利或失利
- 超时处置惩罚
代码以下
class AJAX {
constructor({url = "",method = "GET",data = {},async = true,success,error,resType = "",headers = {}},time = 5000) {
//集合治理通报过来的参数
this.option = {url,method,data,async,success,error,resType,headers,time};
this.timeout;
this.xhr = new XMLHttpRequest();
this.start();
}
start() {
//数据校验
this.checkOption();
//数据花样的一致
this.initOption();
//竖立衔接
this.open();
//设置要求头
this.setHeaders();
//设置返回数据花样
this.setResponseType();
//发送数据
this.sendData()
//返回胜利或失利
this.responseData();
};
}
接下来增加校验功用
- 起首url不能是空
- 然后要求头必需是字面量对象花样 {key:value}
- 再有就是一些简朴的正告
代码以下
checkOption() {
let {url,async,resType,headers,time} = this.option;
if (url === '') {
throw new Error('要求地点不能为空'); //打印毛病信息,并住手当前历程
//Console.error('要求地点为空'); 也可以打印毛病信息,然则不能住手当前历程
}
if(typeof headers !== 'object'){
throw new Error('设置要求头时请传入 {key:value,key:value...} 的花样');
}
if(typeof resType !== 'string'){
throw new Error('设置返回数据花样时请传入字符出串花样');
}
if(typeof time !== 'number'){
throw new Error('超时时候请传入数字范例数据');
}
if (typeof url !== 'string') {
//输出正告信息
console.warn('当前要求地点不是字符串,如今将其尝试转换为字符串');
}
if (async === false && resType != '') {
console.warn('假如设置了要求体式格局为同步,纵然设置了返回数据花样也不会见效');
}
};
须要注重的是返回数据花样可以设置这几个值,以后会写一个细致的传参指南
接下来是数据的处置惩罚
- 起首我们须要保证要求花样,不论传入时是大写照样小写,在我们设置要求花样时如果悉数大写
- 另有就是url多是数字的,须要转换成字符
- 为了轻易将 async不是布尔型的转成布尔型,这是什么观点,就是传参时 写数字 1 是异步 数字 0 是同步
- 将须要发送的内容做一个处置惩罚
initOption() {
let {url,async,method} = this.option;
//url不是字符串转换成字符串
if (typeof url !== 'string') {
try {
this.option.url = url.toString();
console.log(`转换胜利: "${this.option.url}"`);
} catch (error) {
throw new Error('url 转换字符串失利');
}
}
//async不是布尔型转成布尔型
if(typeof async !=='boolean'){
async == true ? this.option.async = true : this.option.async = false;
}
//将 post get 转换为大写
this.option.method = method.toUpperCase();
//post和get数据初始化
if(this.option.method != 'FORMDATA'){// [1]
let data = this.option.data;
if(typeof data === 'object'){//[2]
if( this.option.method === 'GET'){
let arr=[];
for(let name in data){
arr.push(`${name}=${data[name]}`);//[3]
}
let strData=arr.join('&');//[4]
this.option.data=`?${strData}`;//[5]
}else if( this.option.method === 'POST'){
let formData = new FormData();//[6]
for(let key in data){
formData.append(`${key}`,`${data[key]}`);
}
this.option.data=formData;
}
}else if(typeof data === 'string' && this.option.method === 'GET'){//[7]
this.option.data=`?${data}`;
}
}
};
这里细致说说对须要发送数据的处置惩罚,根据序号来讲
- 推断它不是 formData ,也就是说是 GET 和 POST 时我们举行数据处置惩罚,是 formData 不举行处置惩罚,直接发送,这是为了可以完成文件上传功用
- 推断它是否是 {key:vlue} 这类花样的,是的话剖析或拼接,不是的话跳到 [7] 假如是字符串直接加到 url 后边
- [3] [4] [5] 这里是为了处置惩罚成 url?key=value$key=value 这类 url 传参的数据花样
- [6] 是新建了一个 FormData 对象,是 ajax2.0 里边的,它最重要的可以用 ajax 完成文件上传功用,在这里是为了代码简朴
翻开衔接
经由之前的数据处置惩罚这里只须要推断下是 GET 照样其他体式格局(post formdata),然后挑选对应的衔接体式格局
open(){
let {method,url,async,data} = this.option;
if(method === 'GET'){
this.xhr.open(method,url+data,async);
}else{
this.xhr.open(method,url,async);
}
}
设置自定义要求头
将传入的参数举行剖析,然后设置自定义要求头
代码以下
setHeaders(){
let headers = this.option.headers;
for(let key in headers){
this.xhr.setRequestHeader(`${key.toString()}`,`${headers[key].toString()}`)
}
}
设置返回数据花样、发送数据
- 因为同步要求时不能设置返回数据花样,所以做下推断
- 发送数据这里,在经由之前的数据处置惩罚后只要 GET 体式格局有所辨别,其他两种没有辨别(支撑 GET POST 以及我本身定义的一种,更多要求要领可自行扩大)
setResponseType() {
if (this.option.async) {
this.xhr.responseType = this.option.resType;
}
}
增加超时处置惩罚
sendData(){
if(this.option.method == 'GET'){
this.xhr.send();
}else{
this.xhr.send(this.option.data);
}
this.timeout = setTimeout(()=>{
typeof this.option.error === 'function' && this.option.error('要求超时,默许超时时候为 5000 毫秒');
this.option.reject('要求超时,默许超时时候为 5000 毫秒');
}, this.option.time);
}
要求完成后的数据返回
- 要求完成后会返回数据
推断 success 以及 error 是否是函数,是的话会将数据返回给 success 或许将毛病信息返回给 error
responseData(){
this.xhr.onload = ()=>{
if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){
typeof this.option.success === 'function' && this.option.success(this.xhr.response);
}else{
typeof this.option.error === 'function' && this.option.error(this.xhr.statusText);
}
}
}
在完成基础功用后,倏忽想到 jQuery 的 ajax 是会返回一个 promise 对象,可以同时运用回掉函数,或许运用 then 和 catch 来处置惩罚数据
因而修改了下传入参数,以及返回数据的处置惩罚
传参时代码以下
//add resolve reject
class AJAX {
constructor({url = "",method = "GET",data = {},async = true,success,error,resType = "",headers = {},resolve,reject}) {
this.option = {url,method,data,async,success,error,resType,headers,resolve,reject};
this.xhr = new XMLHttpRequest();
this.start();
}
}
返回数据时代码以下
responseData(){
this.xhr.onload = ()=>{
if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){
clearTimeout(this.timeout);
typeof this.option.success === 'function' && this.option.success(this.xhr.response);
this.option.resolve(this.xhr.response);//add
}else{
clearTimeout(this.timeout);
typeof this.option.error === 'function' && this.option.error(this.xhr.statusText);
this.option.reject(this.xhr.statusText);//add
}
}
}
终究代码
class AJAX {
constructor({url = "",method = "GET",data = {},async = true,success,error,resType = "",headers = {},resolve,reject}) {
this.option = {url,method,data,async,success,error,resType,headers,resolve,reject};
this.xhr = new XMLHttpRequest();
this.start();
}
start() {
//数据校验
this.checkOption();
//数据花样的一致
this.initOption();
//竖立衔接
this.open();
//设置要求头
this.setHeaders();
//设置返回数据花样
this.setResponseType();
//发送数据
this.sendData()
//返回胜利或失利
this.responseData();
};
checkOption() {
let {url,async,resType,headers} = this.option;
if (url === '') {
throw new Error('要求地点不能为空'); //打印毛病信息,并住手当前历程
//Console.error('要求地点为空'); 也可以打印毛病信息,然则不能住手当前历程
}
if(typeof headers !== 'object'){
throw new Error('设置要求头时请传入 {key:value,key:value...} 的花样');
}
if(typeof time !== 'number'){
throw new Error('超时时候请传入数字范例数据');
}
if(typeof resType !== 'string'){
throw new Error('设置返回数据花样时请传入字符出串花样');
}
// "" 与设置为"text"雷同, 是默许范例 (实际上是 DOMString)
// "arraybuffer" 将接收到的数据范例视为一个包括二进制数据的 JavaScript ArrayBuffer
// "blob" 将接收到的数据范例视为一个包括二进制数据的 Blob 对象
// "document" 将接收到的数据范例视为一个 HTML Document 或 XML XMLDocument ,这取决于接收到的数据的 MIME 范例
// "json" 将接收到的数据范例视为 JSON 剖析获得的
// "text" 将接收到的数据范例视为包括在 DOMString 对象中的文本
if (typeof url !== 'string') {
//输出正告信息
console.warn('当前要求地点不是字符串,如今将其尝试转换为字符串');
}
if (async === false && resType != '') {
console.warn('假如设置了要求体式格局为同步,纵然设置了返回数据花样也不会见效');
}
};
initOption() {
let {url,async,method} = this.option;
//url不是字符串转换成字符串
if (typeof url !== 'string') {
try {
this.option.url = url.toString();
console.log(`转换胜利: "${this.option.url}"`);
} catch (error) {
throw new Error('url 转换字符串失利');
}
}
//async不是布尔型转成布尔型
if(typeof async !=='boolean'){
async == true ? this.option.async = true : this.option.async = false;
}
//将 post get 转换为大写
this.option.method = method.toUpperCase();
//post和get数据初始化
if(this.option.method != 'FORMDATA'){
let data = this.option.data;
if(typeof data === 'object'){
if( this.option.method === 'GET'){
let arr=[];
for(let name in data){
arr.push(`${name}=${data[name]}`);
}
let strData=arr.join('&');
this.option.data=`?${strData}`;
}else if( this.option.method === 'POST'){
let formData = new FormData();
for(let key in data){
formData.append(`${key}`,`${data[key]}`);
}
this.option.data=formData;
}
}else if(typeof data === 'string' && this.option.method === 'GET'){
this.option.data=`?${data}`;
}
}
};
open(){
let {method,url,async,data} = this.option;
if(method === 'GET'){
this.xhr.open(method,url+data,async);
}else{
this.xhr.open(method,url,async);
}
}
setHeaders(){
let headers = this.option.headers;
for(let key in headers){
this.xhr.setRequestHeader(`${key.toString()}`,`${headers[key].toString()}`)
}
}
setResponseType() {
if (this.option.async) {
this.xhr.responseType = this.option.resType;
}
}
sendData(){
if(this.option.method == 'GET'){
this.xhr.send();
}else{
this.xhr.send(this.option.data);
}
this.timeout = setTimeout(()=>{
typeof this.option.error === 'function' && this.option.error('要求超时,默许超时时候为 5000 毫秒');
this.option.reject('要求超时,默许超时时候为 5000 毫秒');
}, this.option.time);
}
responseData(){
this.xhr.onload = ()=>{
if(this.xhr.status >= 200 && this.xhr.status < 300 || this.xhr.status === 304){
clearTimeout(this.timeout);
typeof this.option.success === 'function' && this.option.success(this.xhr.response);
this.option.resolve(this.xhr.response);//add
}else{
clearTimeout(this.timeout);
typeof this.option.error === 'function' && this.option.error(this.xhr.statusText);
this.option.reject(this.xhr.statusText);//add
}
}
}
all(promises) {
return Promise.all(promises);
};
}
function ajax({url,method,data,async,success,error,resType,headers,time}){
return new Promise((resolve, reject) => {
return new AJAX({url,method,data,async,success,error,resType,headers,time,resolve,reject});
});
}
运用时可以将代码复制粘贴到零丁的 js 文件然后用 script 标签引入
也可以增加一行 export 代码将末了的 ajax 暴露出去 运用import 引入
详细运用要领用法
ajax({
url:'api/login',
method:'post',//支撑 GET POST 和我自定义的 FORMDATA ,传入时不辨别大小写
data = {
name:"yhtx",
id:"1997"
},//除了这类还支撑字符串 "name=yhtx&id=1997";以及 formData 数据,在传入formData 数据时请将 method 设置为 FORMDATA
async = true,//可以运用数字 1 替代 true ,数字 0 替代 false
time = 5000,//要求超时时候,默许为 5000 毫秒
success(res){
//可以运用回调的情势处置惩罚数据也可以运用 then
},error(err){
//可以运用回调的情势处置惩罚毛病也可以运用 catch
},
resType = "",//可以传入 "" "arraybuffer" "blob" "document" "json" "text"
headers = {
mycookie: "46afqwiocibQEIJfa498./&678" //运用对象的体式格局传参
}
}).then((res)=>{
//可以运用 then 的情势处置惩罚数据也可以运用回调函数
}).catch((err)=>{
//可以运用 catch 的情势处置惩罚数据也可以运用回调函数
})