60. ES6+ 封装请求
1. 前言
在学习Promise相关小节时我们已经了解了Promise的基本用法和Promise A+规范,那么在实际项目中我们应该怎么去使用Promise来提高我们的效率,并且可以通过Promise去封装一些异步方法,让我们在使用过程中更加得心应手。
本文我们将模拟一个真实的生产环境来对前端开发中最常见也是最重要的数据请求进行封装。通过使用封装Promise请求来学习Promise在实际项目当中是如何使用的。
2. 环境搭建
工欲善其事,必先利其器,在我们进入本节的学习前,我们需要先搭建我们的开发环境,在实际的项目中也是必须的。本节使用的是Vue脚手架生成的项目,这里默认大家对Vue有了解。在vue.config.js配置中,对ajax请求进行了mock操作,mock的逻辑在mock.config.js文件中,mock的结果在mock文件夹下对应的json。
3. 封装ajax请求
ajax是前端用于发送接口请求的技术,它是异步的,需要等待结果返回后执行。
在发送ajax请求时,我们可能会这样去写。
ajax({ url: '', method: '', data: {}, params: {}, success: function (res) {}, error: function (err) {} })
参数讲解:
url
: 接口请求地址;method
: 接口请求方法,如:get、post等;data
: 请求时使用body传输的数据,一般用于post请求中;params
: 请求时使用url传递的数据,一般用于get请求中;success
: 接口请求成功时的回调,参数为接口成功的返回值;error
: 接口请求失败时的回调,参数为抛出异常时的调用栈等信息。XMLHttpRequest
是浏览器提供的对象,用于进行后台与服务端的数据进行交互
3.1 实现ajax
function ajax(options) { const { url, method, data, params, success, error } = options; const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { // readyState为4的时候已接收完毕 if (xhr.readyState === 4) { // 状态码200表示成功 if (xhr.status === 200) { 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 ? `${url}?${params}` : 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) => { // 创建XMLHttpRequest对象 const xhr = new XMLHttpRequest(); // 状态改变时的回调 xhr.onreadystatechange = function () { // readyState为4的时候已接收完毕 if (xhr.readyState === 4) { // 状态码200表示成功 if (xhr.status === 200) { resolve(xhr.responseText); } else { reject(xhr.status); } } }; // ... }); }
4. axios库封装
在真实的项目中会经常使用到axios这样的ajax请求的库,虽然可以直接使用,但是往往业务中会有很多接口请求的地方,而这么多的请求有些固定不变的,每个接口在请求时都需要,如:token,baseURL,timeout等等,针对这样的场景,我们可以对axios库进行二次业务封装。对于接口不同的返回结果我们希望有一个全局的提示框,这里我们使用element-ui组件库搭配使用。封装后的代码如下:
import axios from 'axios'; import { baseURL } from '@/config' class Http { constructor(baseUrl) { this.baseURL = baseURL; this.timeout = 3000; } setInterceptor(instance) { instance.interceptors.request.use(config => { return config; }); instance.interceptors.response.use(res => { if (res.status == 200) { 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, config = {}) { return this.request({ method: 'get', url: url, ...config }) } post(url, data) { return this.request({ method: 'post', url, data }) } } export default new Http;
5. 小结
本文我们通过真实的业务场景触发,对原生的ajax请求做了promise封装,最后我们对真实的业务场景使用axios对业务二次封装,这样更好地复用业务逻辑,统一增加不同返回结果的提示。