Ajax&Fetch学习笔记 05、ajax封装(含Promise)
【摘要】 文章目录前言一、内部封装js①utils工具类②Defaults.js(默认属性方法配置类)③constant.js(常量文件)④Ajax.js(自定义Ajax类,用来进行初始化执行一系列操作)二、外部封装(提供给外界使用的API,含测试)2.1、Ajax原生封装2.2、Ajax进阶封装Promise
前言
本篇博客是对于Ajax的封装,若文章中出现相关问题,请指出!
所有博客文件目录索引:博客目
@[toc]
前言
本篇博客是对于Ajax的封装,若文章中出现相关问题,请指出!
所有博客文件目录索引:博客目录索引(持续更新)
一、内部封装js
ajax类
初始化方法
绑定响应事件处理
设置各个header
发送请求
utils工具类
constant常量类
default配置类:基本的配置属性
index(对外暴露封装类) 给外界调用的接口
①utils工具类
// 添加url请求参数:data为已经序列化的string值,这里只需要判断url后添加?还是&
const addUrlData = (url, data) => {
if (!data) return '';
// 用于标识是否包含?
const mark = url.includes('?') ? '&' : '?';
return `${mark}${data}`;
}
// 序列化:将传入的对象进行序列化并且进行编码防止有中文文字,如username=changlu&age=18
const serialize = (param) => {
const results = [];
for (const [key, value] of Object.entries(param)) {
results.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
}
return results.join('&');
}
// JSON序列化(对象=>JSON字符串,通常放置在请求体中)
const serializeJSON = (data) => {
return JSON.stringify(data);
}
export { addUrlData, serialize, serializeJSON }
②Defaults.js(默认属性方法配置类)
包含一个xhr
对象的相关属性以及方法,目的是方便设置一些默认值:
- 属性:请求方法、请求头信息、请求体数据、内容类型、响应类型、超时时间、跨域是否携带cookie属性。
- 方法(监听方法):成功事件、响应码方法、报错方法、停止请求方法、超时方法。
import { HTTP_GET, CONTENT_TYPE_FROM_URLENCODED } from './constant.js'
// 默认配置类
const DEFAULTS = {
//请求方法(多个,使用常量文件中的):默认GET请求
method: HTTP_GET,
// 请求头携带的数据:?username=xx&age=xx
params: null,
// 请求体携带的数据:①对象形式。②FormData数据
data: null,
// 内容类型(请求头)
contentType: CONTENT_TYPE_FROM_URLENCODED,
// 响应类型
responseType: '',
// 超时时间
timeout: 0,
// 跨域携带cookie属性
withCredentials: false,
// 监听事件方法
success() { },
httpCodeError() { },//响应码错误
error() { },
abort() { },
timeOut() { }
};
export default DEFAULTS;
③constant.js(常量文件)
目的:将一些常量使用文件管理起来,若是想要修改一个值直接修改配置文件即可,而不是在js中来多次修改常量。
包含如HTTP请求,内容类型以及错误响应码以及描述。
// HTTP请求
export const HTTP_GET = "GET";
// 发送内容类型
export const CONTENT_TYPE_FROM_URLENCODED = 'application/x-www-form-urlencoded';
export const CONTENT_TYPE_FROM_JSON = 'application/json';
// 封装Promise使用
export const ERROR_HTTP_CODE = 1;
export const ERROR_HTTP_CODE_TEXT = 'HTTP状态码异常';
export const ERROR_REQUEST = 2;
export const ERROR_REQUEST_TEXT = '请求被阻止';
export const ERROR_ABORT = 3;
export const ERROR_ABORT_TEXT = '请求停止';
export const ERROR_TIMEOUT = 4;
export const ERROR_TIMEOUT_TEXT = '请求超时';
④Ajax.js(自定义Ajax类,用来进行初始化执行一系列操作)
其中封装了如下的步骤在构造器中:
1、构造器传入url、options初始化。
2、监听事件绑定,如success、error、errorhttpcode、abort、timeout等等,方便外部调用者直接外部写回调函数。
3、open()初始化。(请求方法与请求参数是否拼接)
4、特殊属性定制设置,如ResponseType、timeout、WithCredentials。(这部分是将options配置对象中的值真正赋给xhr对象)
5、发送请求send()。考虑多种请求①发送GET请求,其他为POST请求。②data为FormData类型。③data为x-www-form-urlencoded类型传递。④data为JSON类型传递。⑤其他类型传递。
// 导入配置类
import DEFAULTS from './default.js';
// 导入工具类
import { addUrlData, serialize, serializeJSON } from './utils.js';
// 导入常量类
import {
HTTP_GET,
CONTENT_TYPE_FROM_URLENCODED,
CONTENT_TYPE_FROM_JSON
} from "./constant.js";
class Ajax {
constructor(url, options) {
this.url = url;
this.options = Object.assign({}, DEFAULTS, options);
// 初始化方法
this.init();
}
// 初始化
init() {
const xhr = new XMLHttpRequest();
this.xhr = xhr;
// 绑定事件
this.bindEvents();
xhr.open(this.options.method, this.url + this.addParam(), true);
// 设置属性到xhr中
// 设置响应类型
this.setResponseType();
// 设置超时时间
this.setTimeout();
// 设置跨域是否携带cookie
this.setWithCredentials();
// 发送请求
this.send();
}
// 绑定响应事件处理程序
bindEvents() {
const xhr = this.xhr;
const { success, httpCodeError, error, abort, timeOut } = this.options;
// 绑定监听success事件(通过监听onload事件)
xhr.addEventListener("load", () => {
if (this.ok()) {
success(xhr.response, xhr);
} else {
httpCodeError(xhr.response, xhr);
}
}, false);
// error
xhr.addEventListener("error", () => {
error(xhr);
}, false);
// abort
xhr.addEventListener("abort", () => {
abort(xhr);
}, false);
// timeout
xhr.addEventListener("timeout", () => {
timeOut(xhr);
}, false);
}
// 判断当前状态码是否为成功
ok() {
const xhr = this.xhr;
return (xhr.status >= 200 && xhr.status <= 299) || xhr.status == 304;
}
// 在请求地址上添加数据
addParam() {
const { params } = this.options;
//无请求参数
if (!params) return '';
// 考虑到传入的url地址是否已经带有?,所以传入URL以及params
return addUrlData(this.url, serialize(params));
}
// 设置响应类型
setResponseType() {
this.xhr.responseType = this.options.responseType;
}
// 设置超时时间
setTimeout() {
const { timeout } = this.options;
if (timeout > 0) {
this.xhr.timeout = timeout;
}
}
// 设置是否跨域携带cookie
setWithCredentials() {
const { withCredentials } = this.options;
if (withCredentials) {
this.xhr.withCredentials = withCredentials;
}
}
// 发送请求
send() {
const xhr = this.xhr;
//测试是否需要使用send()来发送数据
if (!this.isSendData()) {
xhr.send(null);
return;
}
// 处理data数据
let resultData;//最终需要发送的data数据
const { data } = this.options;
// 是否为FormData格式数据
if (this.isFormData(data)) {
resultData = data;
} else if (this.isFormURLEncodedData()) {
// console.log("data=>", data);
// 发送类型为application/x-www-form-urlencoded数据
resultData = serialize(data);
this.xhr.setRequestHeader('Content-Type', CONTENT_TYPE_FROM_URLENCODED);
} else if (this.isJSONData()) {
// 发送类型为application/json数据
resultData = serializeJSON(data);
this.xhr.setRequestHeader('Content-Type', CONTENT_TYPE_FROM_JSON);
} else {
this.setContentType();
resultData = data;
}
xhr.send(resultData);
}
// 是否想要使用send()发送数据
isSendData() {
// 根据method以及data来确定
const { method, data } = this.options;
// data没有值或者请求方法为GET返回false
if (!data) return false;
if (method.toLowerCase() === HTTP_GET.toLowerCase())
return false;
return true;
}
// 是否data值为FormData类
isFormData() {
return this.options.data instanceof FormData;
}
// 是否发送 application/x-www-form-urlencoded 格式的数据
isFormURLEncodedData() {
return this.options.contentType
.toLowerCase()
.includes(CONTENT_TYPE_FROM_URLENCODED);
}
// 是否发送 application/json 格式的数据
isJSONData() {
return this.options.contentType
.toLowerCase()
.includes(CONTENT_TYPE_FROM_JSON);
}
// 发送其他类型的数据
setContentType(contentType = this.options.contentType) {
if (!contentType) return;
this.xhr.setRequestHeader("Content-Type", contentType);
}
// 获取xhr对象
getXHR() {
return this.xhr;
}
}
export default Ajax;
二、外部封装(提供给外界使用的API,含测试)
其实本质就是对Ajax类进行二次封装出API来提供为外界使用。
2.1、Ajax原生封装
如ajax、get、getJSON、post方法,这些名称都十分鲜明对应着不同的请求方式:
import Ajax from './ajax.js'
const ajax = (url, options) => {
return new Ajax(url, options).getXHR();
}
const get = (url, options) => {
return ajax(url, {
...options, method: 'GET'
});
}
const getJSON = (url, options) => {
return ajax(url, {
...options, method: 'GET', responseType: 'json'
});
}
const post = (url, options) => {
return ajax(url, {
...options, method: 'POST'
});
}
export { ajax, get, getJSON, post }
测试
<script type="module">
import { ajax, get, getJSON, post } from '../index(原生封装ajax).js'
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const xhr = ajax(url, {
method: 'POST',
data: {
username: 'changlu',
age: 18
},
timeout: 10,
responseType: 'json',
success(response) {
console.log(response);
},
error(xhr) {
console.log("error");
},
abort() {
console.log("abort");
},
timeOut() {
console.log("timeout");
}
});
// xhr.abort();
</script>
2.2、Ajax进阶封装Promise
相较于原生封装有什么优势呢?
- 使用原生封装我们需要在传入对象中写一些回调函数如success、error、abort、timeout等等,这样的话也会造成代码量过多的情况。而使用Promise不再需要编写这些额外回调函数,交由Promise,开发者只需要关注then()与catch()方法即可:success=>then,error、abort、timeout=>catch捕获!!!
下面使用Promise
进行封装,实际上只需要在Ajax原生封装上进行封装Promise即可:
import Ajax from './ajax.js'
// 引入错误码以及错误描述常量
import {
ERROR_HTTP_CODE,
ERROR_REQUEST,
ERROR_TIMEOUT,
ERROR_ABORT,
ERROR_HTTP_CODE_TEXT,
ERROR_REQUEST_TEXT,
ERROR_TIMEOUT_TEXT,
ERROR_ABORT_TEXT
} from './constant.js';
const ajax = (url, options) => {
let xhr;
const p = new Promise((resolve, reject) => {
// 内部对几个方法再次进行封装
xhr = new Ajax(url, {
...options,
...{
//响应成功调用then()方法
success(response) {
resolve(response);
},
//其他情况统一传递给catch()捕捉,传递type以及text属性,分为为错误码以及错误描述
httpCodeError(status) {
reject({
type: ERROR_HTTP_CODE,
text: `${ERROR_HTTP_CODE_TEXT}:${status}`
})
},
error() {
reject({
type: ERROR_REQUEST,
text: ERROR_REQUEST_TEXT
})
},
abort() {
reject({
type: ERROR_ABORT,
text: ERROR_ABORT_TEXT
})
},
timeOut() {
reject({
type: ERROR_TIMEOUT,
text: ERROR_TIMEOUT_TEXT
})
}
}
}).getXHR();;
});
//将xhr对象赋值给promise对象,为方便开发者可以调用到它自己额外做一些操作等
p.xhr = xhr;
p.ERROR_HTTP_CODE = ERROR_HTTP_CODE;
p.ERROR_REQUEST = ERROR_REQUEST;
p.ERROR_TIMEOUT = ERROR_TIMEOUT;
p.ERROR_ABORT = ERROR_ABORT;
return p;//返回Promise对象
}
const get = (url, options) => {
return ajax(url, {
...options, method: 'GET'
});
}
const getJSON = (url, options) => {
return ajax(url, {
...options, method: 'GET', responseType: 'json'
});
}
const post = (url, options) => {
return ajax(url, {
...options, method: 'POST'
});
}
export { ajax, get, getJSON, post }
测试
<script type="module">
import { ajax, get, getJSON, post } from '../index(2封装ajax进阶Promise).js';
const url = 'https://www.imooc.com/api/http/search/suggest?words=js';
const p = getJSON(url, {
params: {
username: 'changlu',
age: 18
},
timeout: 10
});
// 获取到xhr
console.log(p.xhr);
// 执行abort()来进行测试
// p.xhr.abort();
//统一这里来进行结果的处理!!!
p.then((response) => {
console.log(response);
}).catch(error => {
console.log("type=>" + error.type + ",text=>" + error.text);
});
</script>
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)