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