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

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

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

相关推荐
知识分享小能手16 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
魔云连洲16 小时前
深入解析:Vue与React的异步批处理更新机制
前端·vue.js·react.js
mCell17 小时前
JavaScript 的多线程能力:Worker
前端·javascript·浏览器
超级无敌攻城狮18 小时前
3 分钟学会!波浪文字动画超详细教程,从 0 到 1 实现「思考中 / 加载中」高级效果
前端
excel19 小时前
用 TensorFlow.js Node 实现猫图像识别(教学版逐步分解)
前端
gnip19 小时前
JavaScript事件流
前端·javascript
赵得C20 小时前
【前端技巧】Element Table 列标题如何优雅添加 Tooltip 提示?
前端·elementui·vue·table组件
wow_DG20 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(一):响应式原理
前端·javascript·vue.js
weixin_4569042720 小时前
UserManagement.vue和Profile.vue详细解释
前端·javascript·vue.js
资深前端之路20 小时前
react 面试题 react 有什么特点?
前端·react.js·面试·前端框架