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

  • 先说一下业务场景:项目中有一个提交测算的按钮,点击后首先会进行页面切换,在新页面中需要持续从后端获取测算结果,根据结果进行不同的业务展示。
  • 所以在新页面挂载之后我们需要做的是:以固定的时间间隔去调用后端所提供的接口。首先可以想到定时器 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);
    });
  };

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

相关推荐
hhcccchh5 小时前
1.2 CSS 基础选择器、盒模型、flex 布局、grid 布局
前端·css·css3
专吃海绵宝宝菠萝屋的派大星6 小时前
使用Dify对接自己开发的mcp
java·服务器·前端
爱分享的阿Q6 小时前
Rust加WebAssembly前端性能革命实践指南
前端·rust·wasm
蓝黑20206 小时前
Vue的 value=“1“ 和 :value=“1“ 有什么区别
前端·javascript·vue
小李子呢02116 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
He少年7 小时前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
史迪仔01127 小时前
[QML] QML IMage图像处理
开发语言·前端·javascript·c++·qt
AwesomeCPA7 小时前
Miaoduo MCP 使用指南(VDI内网环境)
前端·ui·ai编程
前端大波7 小时前
前端面试通关包(2026版,完整版)
前端·面试·职场和发展
qq_433502187 小时前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书