ES6 实战2-封装请求
在学习 Promise 相关小节时我们已经了解了 Promise 的基本和 Promise A + 规范,那么在实际项目中我们应该怎么去使用 Promise 来提高我们的效率,并且可以通过 Promise 去封装一些,让我们在使用过程中更加得心应手。
本节我们将模拟真实的生产环境来对前端开发中最常见也是最重要的数据请求进行封装。通过使用封装 Promise 请求来学习 Promise 在实际项目当中是如何使用的。
工欲善其事,必先利其器,在我们进入本节的学习前,我们需要先搭建我们的开发环境,在实际的项目中也是必须的。本节使用的是 Vue 脚手架的项目,不了解 Vue 的同学可以先去学习一下。在 vue.con.js 配置中,对 ajax 请求进行了 mock 操作,mock 的逻辑在 mock.con.js 中,mock 的结果在 mock 夹下对应的 json。
这样的配置在本节中就可以基本模拟真实的数据请求过程了,本节的源码在 上。
ajax 是前端用于发送接口请求的技术,它是异步的,需要等待结果返回
在发送 ajax 请求时,我们可能会这样去写。
ajax({
url: '',
method: '',
data: {},
params: {},
success: function (res) {},
error: function (err) {}
})
XMLHttpRequest 是浏览器提供的对象,用于进行与服务端的数据进行交互
function ajax(options) {
const { url, method, data, params, success, error } = options;
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
// readyState为4的时候已接收完毕
if (xhr.readyState === ) {
// 状态码200表示成功
if (xhr.status === ) {
console.log(xhr.responseText);
success.call(this, xhr.responseText);
} else {
console.log(xhr.status);
error.call(this, xhr.status)
}
}
};
// get 请求
if (method === 'get' || method === 'GET') {
if (typeof params === 'object') {
// params拆解成字符串
params = Object.keys(params).map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
}
url = params ? `@H_911_@${url@H_911_@}?@H_911_@${params@H_911_@}` : url;
xhr.open(method, url, true);
xhr.send();
}
// post 请求
if (method === 'post' || method === 'POST') {
xhr.open(method, url, true);
xhr.setRequestHeader("Content-type", "application/json; charset=utf-8");
xhr.send(JSON.stringify(params));
}
}
使用 promise 进行封装
function ajax(url, method, params) {
return new Promise((resolve, reject) => {
// HttpRequest对象
const xhr = new XMLHttpRequest();
// 状态改变时的回调
xhr.onreadystatechange = function () {
// readyState为4的时候已接收完毕
if (xhr.readyState === ) {
// 状态码200表示成功
if (xhr.status === ) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
}
};
// ...
});
}
在真实的项目中会经常使用到 axios 这样的 ajax 请求的库,虽然可以直接使用,但是往往业务中会有很多接口请求的地方,而这么多的请求有些固定不变的,每个接口在请求时都需要,如:token,baseURL,timeout 等等,针对这样的场景,我们可以对 axios 库进行二次业务封装。对于接口不同的返回结果我们希望有全局的框,这里我们使用 element-ui 组件库搭配使用。封装后的如下:
import axios from 'axios';
import { baseURL } from '@/con'
class Http {
constructor(baseUrl) {
this.baseURL = baseURL;
this.timeout = ;
}
setInterceptor(instance) {
instance.interceptors.request.use(con => {
return con;
});
instance.interceptors.response.use(res => {
if (res.status == ) {
return Promise.resolve(res.data);
} else {
return Promise.reject(res);
}
}, err => {
return Promise.reject(err);
});
}
mergeOptions(options) {
return {
baseURL: this.baseURL,
timeout: this.timeout,
...options
}
}
request(options) {
const instance = axios.create();
const opts = this.mergeOptions(options);
this.setInterceptor(instance);
return instance(opts);
}
get(url, con = {}) {
return this.request({
method: 'get',
url: url,
...con
})
}
post(url, data) {
return this.request({
method: 'post',
url,
data
})
}
}
export default new Http;
本节我们通过真实的业务场景触发,对原生的 ajax 请求做了 promise 封装,最后我们对真实的业务场景使用 axios 对业务二次封装,这样更好地复用业务逻辑,统一不同返回结果的。