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

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

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

相关推荐
像风一样自由202044 分钟前
HTML与JavaScript:构建动态交互式Web页面的基石
前端·javascript·html
aiprtem1 小时前
基于Flutter的web登录设计
前端·flutter
浪裡遊1 小时前
React Hooks全面解析:从基础到高级的实用指南
开发语言·前端·javascript·react.js·node.js·ecmascript·php
why技术2 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
GISer_Jing2 小时前
0704-0706上海,又聚上了
前端·新浪微博
止观止2 小时前
深入探索 pnpm:高效磁盘利用与灵活的包管理解决方案
前端·pnpm·前端工程化·包管理器
whale fall2 小时前
npm install安装的node_modules是什么
前端·npm·node.js
烛阴2 小时前
简单入门Python装饰器
前端·python
袁煦丞3 小时前
数据库设计神器DrawDB:cpolar内网穿透实验室第595个成功挑战
前端·程序员·远程工作
天天扭码3 小时前
从图片到语音:我是如何用两大模型API打造沉浸式英语学习工具的
前端·人工智能·github