之前在小程序中封装了ajax工具,并对消息队列做了处理。但是其中很多业务代码混杂再其中,故对其进一步抽象化,将业务代码分离出来。
业务代码主要存在于request的请求和响应阶段,仿照axios做一个拦截器,将其中的业务代码通过拦截器传递进来执行。
改写为类
首先对Alipay工具类进行改造,将公用方法放到原型上,使用时新建一个实例。类的create方法接收一些全局参数,返回一个实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| class Alipay { constructor (option = {}) { this.baseURL = option.baseURL || '' this.timeout = option.timeout || 30000 this.concurrency = option.concurrency || 6 this.useMock = option.useMock this.locking = false this.lockQueue = [] this.queue = [] this.subQueue = [] this.count = 0 }
static create (option) { return new Alipay(option) } }
Alipay.prototype.walk = function () { }
Alipay.prototype.http = function (options = {}) { }
Alipay.prototype.lock = function () { }
Alipay.prototype.unlock = function () { }
Alipay.prototype.request = function (options) { }
Alipay.prototype.get = function (options) { }
Alipay.prototype.post = function (options) { }
module.exports = Alipay
|
拦截器
然后新建一个Interceptor类。
1 2 3 4 5 6 7 8 9
| class Interceptor { constructor (option) { this.use = (cb = null, errCb = null) => { option.cb = cb option.errCb = errCb } this.eject = null } }
|
在Alipay上添加interceptors属性,并在request时执行拦截器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| class Alipay { constructor (option = {}) { this.requestConfig = {} this.responseConfig = {} this.interceptors = { request: new Interceptor(this.requestConfig), response: new Interceptor(this.responseConfig), } } }
Alipay.prototype.request = function (options) { const self = this options = { method: 'GET', data: {}, headers: {}, baseURL: self.baseURL, timeout: self.timeout, ...options, }
return new Promise((resolve, reject) => { if (self.requestConfig.cb) { resolve(self.requestConfig.cb(options)) } else { resolve(options) } }) .then((options) => { const { route, url, baseURL, loading, subQueue, ...params } = options my.request({ url: baseURL + url, ...params, success: (res) => { return new Promise((resolve2, reject2) => { if (self.responseConfig.cb) { resolve2(self.responseConfig.cb(res.data, options)) } else { resolve2(res.data) } }) .then(data => { resolve(data) self.count-- self.walk() }) .catch(err => { return new Promise((resolve3, reject3) => { if (self.responseConfig.errCb) { resolve3(self.responseConfig.errCb(err, options)) } else { resolve3(err) } }) .then(err => { reject(err) self.count-- self.walk() }) }) }, fail: (err, options) => { return new Promise((resolve4, reject4) => { if (self.responseConfig.errCb) { resolve4(self.responseConfig.errCb(err, options)) } else { resolve4(err) } }) .then(err => { reject(err) self.count-- self.walk() }) } }) }) .catch(err => { return new Promise((resolve5, reject5) => { if (self.requestConfig.errCb) { resolve5(self.requestConfig.errCb(err, options)) } else { resolve5(err) } }) .then(err => { reject(err) self.count-- self.walk() }) }) }
|
这里其实axios存放的回调函数是一个数组,可以多次使用use方法,并能够用eject方法来取消。这里先偷个懒,暂时只接收一个。在业务代码中传入拦截器函数,然后Alipay中执行request时,如果有拦截器函数,会先执行,再去request;响应时也是先判断拦截器,再去执行后续操作。这样,就可以把业务代码分离到api文件中。
拦截器使用
将业务代码分离出来,写到这里。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import { md5 } from '../libs/md5' const Alipay = require('./Alipay') const config = require('../config.js')
const instance = Alipay.create({ useMock: false, baseURL: config.url, timeout: 30000, concurrency: 6, })
instance.interceptors.request.use( config => { return config } )
instance.interceptors.response.use( (response, config) => { return response }, (err, config) => { console.log(err) return Promise.reject(err) } )
module.exports = { lock () { return instance.lock() }, unlock () { return instance.unlock() },
getUid (options) { return instance.http({ url: '/user/queryUid', method: 'GET', ...options }) }, burydata (options) { return instance.http({ url: '/hcz/burydata', baseURL: config.maidianUrl, method: 'POST', subQueue: true, ...options }) }, ... }
|
对原先阻塞队列的修改
有了类,我们可以生成多个alipay实例,这样原先的blockQueue就可以去掉了,lock时正常push,但是锁定当前实例所有请求。可以用另一个实例去发送需要的请求,返回时解锁原先实例。
这样就可以在中途锁定队列,修改token、uid之类的数据,而不用担心原先队列的请求发出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| const Alipay = require('./Alipay') const config = require('../config.js')
const instance = Alipay.create({ useMock: false, baseURL: config.url, timeout: 30000, concurrency: 6, })
const instance2 = Alipay.create({ useMock: false, baseURL: config.url, timeout: 30000, concurrency: 6, })
const requestInterceptorFunc = config => { return config } instance.interceptors.request.use( config => { return requestInterceptorFunc(config) } ) instance2.interceptors.request.use( requestInterceptorFunc )
const responseInterceptorFunc = (response, config) => { return response } const responseInterceptorErrFunc = (err, config) => { return Promise.reject(err) } instance.interceptors.response.use( responseInterceptorFunc, responseInterceptorErrFunc, ) instance2.interceptors.response.use( responseInterceptorFunc, responseInterceptorErrFunc, )
const getInstance = { get (options) { options.method = 'GET' return getInstance.http(options) }, post (options) { options.method = 'POST' return getInstance.http(options) }, http (options) { const { useInstance2, ...others } = options if (options.useInstance2) { return instance2.http(others) } else { return instance.http(others) } }, }
module.exports = { lock () { return instance.lock() }, unlock () { return instance.unlock() },
getUid (options) { return getInstance.http({ url: '/user/queryUid', method: 'GET', ...options }) }, ... }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const Api = require('./apis/Api')
App({ onLaunch () { Api.lock() Promise.all([ Api.getUid({ useInstance2: true }), Api.getMaiDian({ useInstance2: true }), ]) .then((reses) => { Api.unlock() }) .catch(() => { }) }, })
|