最近在开发微信小程序, 在测试时, 总能碰到一些诸如网络被打断啊之类的问题. 小程序是一款实时互动的小程序, 基于一系列原因, 没有使用Socket, 而是使用的是长链接. 所以对这类问题不能大意啊, 一个请求断了, 后面的实时状态就无从谈起了.
最简单的啊, 就是对这个长链接捕获错误, 然后重试呗! 当然, 实现这个很简单, 没两行代码就搞定了. 我还做了断网之类的验证, 单单规避这个长链接的错误, 完全OK的.
但是还有很多其他请求哇, 做断网重连的测试的时候, 能导致一些其他未知的影响(当然,不断网的情况下这些是不存在的), (个人处女座, 追求完美)于是我就决定从网络请求的底层, 写入重试机制.
整个项目是Web短和小程序端的实时互动, 为了公用一套类库, 我对所有Web和小程序端的底层接口都做了封装, 以达到公用类库的目的, 而重试机制我只准备给小程序做, Web端是内部使用的, 出现极端情况, 让他刷新一下咯, 而且这种概率很小, 就不考虑了.
首先描述一下我的重试机制的思路, 当任何一个请求发生错误之后, 进行捕获, 进行十次重试, 每次的时间间隔都比上次长, 十次之后, 提示用户网络故障是否要重试, 用户点是之后会再次重试十次, 依次规律, 直至网络请求成功.
const _retryTimes: number = 10; class JeResolve { protected promise: Promise<NetRes<any>> protected _resolve: (value: NetRes<any>) => void | PromiseLike<void>; protected _reject: (reason: any) => void; protected reqOptions: RequestOptions; protected requestObj: RequestTask; protected Listener: JeSysListener = new JeSysListener(this); constructor() { this.promise = new Promise((resolve, reject) => { this._resolve = resolve; this._reject = reject; }); } request<T>(options?: RequestOptions | undefined): IResolve<T> { if (options) { this.retryTimes = 0; options.url = commonService.getUrl(options.url); this.reqOptions = options; this.reqOptions.success = (res: any) => { this.Listener.UnListen(); this._resolve(res); }; this.reqOptions.fail = (res: any) => { if (this.retryTimes < _retryTimes) { this.retryTimes++; if (!this.isAbort) { setTimeout(() => { if (this.retryTimes < _retryTimes + 1 && !this.isAbort) { this.requestObj = uni.request(this.reqOptions); } }, 100 * this.retryTimes); } } else { systemService.raiseRetryTimedout(); } }; this.requestObj = uni.request(this.reqOptions); } return this; } resolve<T>(call: (res: T) => void): IAbort { this.promise.then(res => { call(res.data); }); return this; } abort() { this.Listener.UnListen(); this.requestObj.abort(); this.isAbort = true; } protected retryTimes: number = 0; protected isAbort: boolean = false; onRetryedSuccess(event: SysEvent): void { this.retryTimes = 0; this.requestObj = uni.request(this.reqOptions); } onRetryedTimesout(event: SysEvent): void { this.retryTimes = _retryTimes; } }
以上是我基于Promise自己封装的请求类, 上面很容易看懂, 最底下两个方法解释一下, 是自己分封装的全局的事件的触发以及监听.
主要逻辑:
1、当某个请求重试超过十次之后触发请求超时的事件, 全局会对事件进行一个过滤, 上次事件没有被用户反馈之前, 多个请求接连触发超时会自动过滤掉.
2、在用户点击确定重试之后, 会触发一个确定重试的事件, 所有失败的请求都能监听到这个事件, 开始新的十次重试.
觉得这个挺好玩的, 才写出来, 还不够完善, 感兴趣的道友批评指正.