面试官:来, 实现一个基于promise的请求重试吧

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

背景

实现一个函数 实现一个重试功能,当异步任务失败时,等待N秒后会自动重试直到成功或达到最大重试次数。

const query = () => {
    return fetch(
        'https://api.juejin.cn/user_api/v1/user/dynamic?user_id=3649990025815853&cursor=0&aid=2608&uuid=7387740407814587904&spider=0',
    );
};

代码实现

/**
 *
 * @param task  返回一个promise的异步任务
 * @param count 需要重试的次数
 * @param time  每次重试间隔多久
 * @returns 返回一个新promise
 */
const retry = (task, count = 5, time = 3 * 1000) => {
    return new Promise((_res, _rej) => {
        let doneCount = 0;
        const run = () => {
            task()
                .then(data => {
                    _res(data);
                })
                .catch(err => {
                    doneCount++;
                    if (doneCount > count) {
                        _rej(err);
                    } else {
                        setTimeout(run, time);
                    }
                });
        };
        run();
    });
};

retry(query);

代码分析

  • query 函数返回一个 fetch 请求的结果,这个结果是一个 Promise

  • retry 函数创建并返回一个新的 Promise,内部使用递归和 setTimeout 来实现重试逻辑。

  • 每次 task 执行失败时,catch 块会捕获错误,并增加 doneCount 计数器。

  • 如果 doneCount 超过了 countretry 函数会拒绝 Promise 并传递错误。

  • 如果没有超过重试次数,setTimeout 会延迟执行 run 函数,从而实现重试。

知识点

fetch API

  1. 用于发起网络请求,获取资源。fetch 返回一个 Promise 对象,可以链式调用 .then().catch() 处理响应和错误;

  2. fetch()采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象);

  3. 通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。

更多关于fetch使用[1] 可以参考这篇文章。

**Promise**:

当前主流的js异步编程方案中 都是基于promise的。promise最大的优点就是统一了异步调用的api,所有异步操作都可以使用相同的模式来处理问题。使用链式调用,避免了回调地狱。
promise本质是一个存储回调的容器. 1689543f16ac1379ade75db2266b1b7c.jpeg 更多关于promise的知识点可以参考这篇文章。promise的本质[2]

异步控制流 Asynchronous Control Flow

"异步控制流"是指在编程中,特别是在涉及异步操作(如I/O操作、网络请求等)的编程中,管理和控制这些操作执行顺序和时间点的方法和策略。例如上面是通过 PromisesetTimeout 来控制异步操作的执行顺序。

在JavaScript中,由于其单线程的特性,异步控制流尤为重要,因为它允许程序在等待异步操作完成时继续执行其他代码,从而提高效率和响应性。
异步控制流还包括错误处理机制,确保当异步操作失败时,程序能够适当地响应并继续执行。
在异步控制流中,可以控制多个异步操作的并发执行,以及它们之间的同步关系,例如,只有在前一个异步操作完成后,才开始下一个操作。
合理的异步控制流可以减少等待时间,提高程序性能,特别是在I/O密集型或网络请求密集型的应用中。

递归

run 函数通过递归调用自身来实现重试逻辑。每次请求失败后,会等待指定的时间间隔,然后再次尝试执行 task

在JavaScript中,递归是指一个函数在其内部直接或间接地调用自身。递归通常用于解决一些具有自相似性的问题,即问题可以通过缩小或分解为相似的子问题来求解。在递归中,通常有以下两个关键部分:

  1. 基本情况(Base case):用于标识问题规模最小时的解决方案。基本情况是直接可解的,不需要递归求解。递归在到达基本情况时停止。

  2. 递归规模递减(Recursive case):把问题分解成更小规模的子问题,并调用自身来解决这些子问题。每次递归调用时,问题规模都应该减小,最终收敛到基本情况。

例如:

function fibonacci(n) {
  // 基本情况 (n为0或1时,直接返回n)
  if (n === 0 || n === 1) {
    return n;
  }
  // 递归规模递减(求解子问题)
  else {
    return fibonacci(n - 1) + fibonacci(n - 2);
  }
}

递归在使用时需要格外注意,因为不合适或错误地使用递归可能导致栈溢出(调用栈的大小超过限制)或死循环。为了避免这些问题,请确保问题每次递归调用时都缩小了规模,并且在到达基本情况时停止递归。

闭包

run 函数是一个闭包,它可以访问其外部作用域的变量,如 doneCountd0af7898fc07cc09d1eb97b28a491c2a.jpeg

闭包的本质是函数,捕获了其静态词法作用域,从而形成了作用域链。这使得函数能够跨越其定义环境访问外部变量,是对作用域链和内存引用管理的深刻理解。

闭包揭示了 JavaScript 函数作为一等公民的重要特征。函数不仅可以作为值传递,还能保留其定义时的上下文,这为函数式编程提供了强大支持。

通过闭包,我们能够创建私有变量、实现数据封装和模块化,提升代码的安全性和可维护性。因此,掌握闭包是全面理解和高效使用 JavaScript 的关键。

更多关于闭包的知识点 参考这篇文章 js三座大山之函数闭包[3]

使用示例:

请求成功的case:

4adccf9f121fdf4165934bc3b9d51634.jpeg

截屏2024-07-25 下午4.54.58.png

请求失败的case:

1d9e8fece1691739be658e4c177ed599.jpeg

截屏2024-07-25 下午4.56.41.png

第N次成功

let exeCount = 0;
const query2 = () => {
    return new Promise((_res, _rej) => {
        setTimeout(() => {
            ++exeCount > 3 ? _res(exeCount) : _rej();
        }, 1000);
    });
};

retry(query2)
    .then(res => {
        console.log('succ:', res);
    })
    .catch(err => {
        console.log('err:', err);
    });

重试了3次后第四次 请求成功 返回最终结果840dfd460b7e2d44f90e9643cf496992.jpeg

github仓库

源码 retry[4]

更多基于promise的 优化js运行时的解决方案 run-time-opti[5]

本库长期维护更新...

作者:某某某人

原文链接:https://juejin.cn/post/7395623789135265827

25f7149e2f1a40c737db5ab30b49105c.png

往期推荐

这几个前端组件库有点厉害!

fb95170f4c0e1bd94a1f515868e61381.png

基于 Three.js 的 3D 模型加载优化

75cc0d57bc4b802d0e6ae8e840654b5f.png

30+ 个工作中常用到的前端小知识(干货)

dc76c984e78661ab9d791689532ab798.png


最后

  • 欢迎加我微信,拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

58aad1fa326d8d54208a356480cda081.jpeg

220e12ae1562348cb970cba2d87a4120.png

点个在看支持我吧

82e29f7d5bbe9159acf3b140e8426c55.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
信息数据从传统到当代,是一直在变革当中,突如其来的互联网让传统的信息管理看到了革命性的曙光,因为传统信息管理从时效性,还是安全性,还是可操作性等各个方面来讲,遇到了互联网时代才发现能补上自古以来的短板,有效的提升管理的效率和业务水平。传统的管理模式,时间越久管理的内容越多,也需要更多的人来对数据进行整理,并且数据的汇总查询方面效率也是极其的低下,并且数据安全方面永远不会保证安全性能。结合数据内容管理的种种缺点,在互联网时代都可以得到有效的补充。结合先进的互联网技术,开发符合需求的软件,让数据内容管理不管是从录入的及时性,查看的及时性还是汇总分析的及时性,都能让正确率达到最高,管理更加的科学和便捷。本次开发的高校科研信息管理系统实现了操作日志管理、字典管理、反馈管理、公告管理、科研成果管理、科研项目管理、通知管理、学术活动管理、学院部门管理、科研人员管理、管理员管理等功能。系统用到了关系型数据库中王者MySql作为系统的数据库,有效的对数据进行安全的存储,有效的备份,对数据可靠性方面得到了保证。并且程序也具备程序需求的所有功能,使得操作性还是安全性都大大提高,让高校科研信息管理系统更能从理念走到现实,确确实实的让人们提升信息处理效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值