前端项目中遇到的轮询~轮询的几种实现方式

  • 先说一下业务场景:项目中有一个提交测算的按钮,点击后首先会进行页面切换,在新页面中需要持续从后端获取测算结果,根据结果进行不同的业务展示。
  • 所以在新页面挂载之后我们需要做的是:以固定的时间间隔去调用后端所提供的接口。首先可以想到定时器 setInterval() , 其次也可以根据递归➕ setTimeout() 来实现!
  1. 递归➕ setTimeout()
  • 首先定义轮询函数 polling ,返回一个 Promise 对象,为控制轮询频率,传入参数 delay,默认为 3000ms
  • 在函数中请求后端接口,根据返回值进行不同的操作:1️⃣ 若请求成功但测算结果未出(errno = 0isFinished = false ),采用定时器 setTimeoutdelay 后再次递归调用轮询函数;2️⃣ 若请求成功且测算结果已出(errno = 0isFinished = true ),将调用 resolve() 函数反对成功状态、promiseState 为后端返回的数据的 Promise 对象; 3️⃣ 若请求失败,则返回失败状态的 Promise 对象。

实现如下:

js 复制代码
const polling = (delay = 3000) => new Promise((resolve, reject) => {
    getUpdateRecord(resultIds).then((res: any = {}) => {
      const { errno } = res;
      const data = res?.data;
      if (errno * 1 === 0 && data.isFinished === false) {
        // 接口返回成功,但isFinished为false
        timeout = setTimeout(() => {
          resolve(polling(delay));
        }, delay)
      } else if (errno * 1 === 0 && data.isFinished === true) {
        // 接口返回成功,但isFinished为true
        resolve(res);
      } else {
        // 接口报错
        reject(res);
      }
    });
  });

调用:

js 复制代码
 useEffect(() => {
    try {
      polling(3000).then((res: any) => {
        if (res?.errno * 1 === 0 && res?.data.isFinished === true) {
          setFileUrl(res.data.fileUrl)
          setIsLoading(false)
        }
      })
    } catch (error: any) {
      message.error('请求错误', error.errmsg)
    }
    return () => {
      clearTimeout(timeout)
    }
  }, [])

同样的思路也可以采用 async/await 实现:

js 复制代码
 const polling = async (delay = 3000): Promise<any> => {
    const res = await getUpdateRecord(resultIds);
    const { errno } = res;
    const data = res?.data;
    if (errno * 1 === 0 && data.isFinished === false) {
      // 接口返回成功,但isFinished为false
       await new Promise(resolve => setTimeout(resolve, delay));
       return polling(delay);
    } else if (errno * 1 === 0 && data.isFinished === true) {
      // 接口返回成功,但isFinished为true
       return res;
    } else {
      // 接口报错
       throw res;
    }
  };
  1. setInterval()

    使用 setInterval 可以避免递归调用带来的一些潜在问题,例如栈溢出风险,不过要注意在合适的时候清除定时器。

js 复制代码
 const polling = (delay = 3000) => {
    return new Promise((resolve, reject) => {
      const intervalId = setInterval(async () => {
        const res = await getUpdateRecord(resultIds);
        const { errno } = res;
        const data = res?.data;
        if (errno * 1 === 0 && data.isFinished === false) {
          // 接口返回成功,但isFinished为false
          return;
        } else if (errno * 1 === 0 && data.isFinished === true) {
          // 接口返回成功,但isFinished为true
          clearInterval(intervalId);
          resolve(res);
        } else {
          // 接口报错
          clearInterval(intervalId);
          reject(res);
        }
      }, delay);
    });
  };

今天的总结就到这啦~想起再改,欢迎指正

相关推荐
徐小夕7 小时前
花了3天,我写了一款开源AI公众号编辑器
前端·vue.js·github
PBitW7 小时前
git 中容易遗忘的点 (二) ⚡⚡⚡
前端·git·面试
Hilaku7 小时前
2026 年前端大洗牌:React 服务端到 Vite 的底层重构
前端·javascript·程序员
PBitW7 小时前
git 中容易遗忘的点 (三) 🚀🚀🚀
前端·git·面试
名字还没想好☜7 小时前
React setState 连续调用「丢更新」排查:批量更新与函数式更新
前端·javascript·react.js·react·usestate
come112348 小时前
Vue 2 与 Vue 3 语法区别及使用技巧
前端·javascript·vue.js
腻害兔8 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:ERP 企业资源模块,一个轻量级进销存的完整实现?
前端·javascript·vue.js·人工智能·前端框架·产品经理·ai编程
虹科网络安全8 小时前
艾体宝新闻|从 SQL 注入到服务器接管:CVE-2026-57517 暴露 Web 管理面板的供应链与安全编码风险
服务器·前端·sql
糖果店的幽灵8 小时前
langgraph的四种state解析
java·前端·javascript·langgraph
顺颂时绥_18 小时前
前端大图片压缩与安卓/苹果设备矫正实践
前端