最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端重试策略 - 指数退避算法

    正文概述 掘金(descire)   2021-07-07   483

    前言

      在日常的开发过程中,由于接口的不稳定性,又或者是网络抖动导致的单次接口请求失败,需要前端通过重试策略,来解决系统不可用的问题。

      接下来我们一起探索前端最佳的重试策略。

    基础实现

      对于基础扎实的前端同学来说,可以很容易地想到如下实现:

    /**
     * 重试方法
     * @param {Function} fn 异步函数
     * @param {number} times 重试次数
     * @param {number} timeout 重试等待时间
     * @returns 
     */
    function retry (fn, times, timeout) {
      return new Promise((resolve, reject) => {
        const attemp = () => {
          fn().then(resolve).catch(err => {
            if (times === 0) {
              return reject(err)
            }
            times--;
            setTimeout(attemp, timeout);
          });
        }

        attemp();
      });
    }

    retry(fetchData, 3, 1000);

      上述代码基于 Promise 机制,通过拦截异步请求的 reject 状态,完成异步请求失败的重试操作。

      整体的实现逻辑是没啥问题的,但是一个优秀的重试机制需要考虑如何设置一个适当的重试等待时间。

    指数退避算法

      指数退避算法正是解决如何设置适当的重试等待时间的算法,它的处理流程如下:

    • 客户端发起网络请求。
    • 如果请求失败,等待 1 + random_number_milliseconds 秒之后再重试请求。
    • 如果请求失败,等待 2 + random_number_milliseconds 秒之后再重试请求。
    • 如果请求失败,等待 4 + random_number_milliseconds 秒之后再重试请求。
    • 依此类推,等待时间的上限为 maximum_backoff。

      在指数退避算法中重试等待时间为:

      Math.min((2 ** n + random_number_milliseconds), maximum_backoff)

      这里的 random_number_milliseconds 是小于或等于 1000 的毫秒数(随机值)。这有助于避免出现以下情况:许多客户端同步进行处理并同时执行重试操作,导致同步发送每一波请求。每次重试请求后,系统都会重新计算 random_number_milliseconds 值。

    /**
     * 生成重试等待时间
     * @param {number} times 重试次数
     * @param {number} maximum_backoff 最大等待秒数
     * @returns 
     */
    function createTimeout(times, maximum_backoff) {
      const random_number_milliseconds = Math.floor(Math.random() * 1000);
      return Math.min(Math.pow(2, times) * 1000 + random_number_milliseconds, maximum_backoff);
    }

      根据算法描述,可以实现上述函数来生成重试等待时间。

      接下来,就可以在进行网络请求之前生成重试等待时间列表,以便后续重试使用。

    const maximum_backoff = 64 * 1000;
    function retry (fn, times) {
      const operationTimeout = [];
      for (let i = 0; i < times; i++) {
        operationTimeout.push(createTimeout(i, maximum_backoff));
      }

      return new Promise((resolve, reject) => {
        const attemp = () => {
          fn().then(resolve).catch(err => {
            if (times === 0) {
              return reject(err)
            }
            times--;
            setTimeout(attemp, operationTimeout.shift());
          });
        }

        attemp();
      });
    }

      达到 maximum_backoff 时间后可以选择继续重试,但是如果请求系统处于长时间不可用的状态,客户端重试再多次都是没有意义的,所以可以设置一个 deadline 时间上限,达到上限之后不再重试。

    const maximum_backoff = 64 * 1000;
    function retry (fn, times, deadline) {
      const operationTimeout = [];
      for (let i = 0; i < times; i++) {
        if (deadline < 0) {
          break;
        }
        const timeout = createTimeout(i, maximum_backoff);
        deadline -= timeout;
        operationTimeout.push(timeout);
      }

      times = operationTimeout.length;

      return new Promise((resolve, reject) => {
        const attemp = () => {
          fn().then(resolve).catch(err => {
            if (times === 0) {
              return reject(err)
            }
            times--;
            setTimeout(attemp, operationTimeout.shift());
          });
        }

        attemp();
      });
    }

    总结

      以上就是本文的全部内容,希望能够给你带来帮助,欢迎「关注」「点赞」「转发」

      参考文档:https://cloud.google.com/storage/docs/retry-strategy?hl=zh-cn


    起源地下载网 » 前端重试策略 - 指数退避算法

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元