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

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

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

相关推荐
迅猛龙办公室4 小时前
Python输出当前计算机的系统日期和时间
开发语言·前端·python
小狼154544 小时前
浏览器扩展脚本为什么有时候不生效:注入时机、iframe 和单页路由,多多开票助手
前端·chrome
じòぴé南冸じょうげん5 小时前
油猴脚本突然发现变成灰色了,无法使用?页面不生效?刷新页面没反应?
前端
Csvn6 小时前
组合式 API(Composition API)
前端
火柴就是我7 小时前
Android 打包报错 25.0.3
android·前端
BD_Marathon7 小时前
消息对象中字段的说明
java·前端·python
八荒启·交互动画7 小时前
Web特效025—用 Canvas 2D 做Web特效的定义与边界:这支画笔能做到哪一步
前端·webgl·网页特效·八荒启-交互动画·八荒启
Ai-_Man7 小时前
您您这可以把Dola的多个会话比如说。左侧的多个会话一次性导出吗?不是单条会话里面的多次会对话。用AI导出鸭,答案是可以的
开发语言·前端·人工智能·小程序
excel8 小时前
Nuxt 中使用 useHead 优化 SEO 与 GEO
前端
IT_陈寒9 小时前
SpringBoot启动慢得像蜗牛?原来是这个配置在捣鬼
前端·人工智能·后端