微信小程序的网络重试机制

  最近在开发微信小程序, 在测试时, 总能碰到一些诸如网络被打断啊之类的问题. 小程序是一款实时互动的小程序, 基于一系列原因, 没有使用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、在用户点击确定重试之后, 会触发一个确定重试的事件, 所有失败的请求都能监听到这个事件, 开始新的十次重试.

觉得这个挺好玩的, 才写出来, 还不够完善, 感兴趣的道友批评指正.