20行代码,借助scheduler实现递归轮询类

业务场景复现

彦祖们, 假设你开了一家 4s 店, 店名叫做 Tesla·Qin

你想定时查看店内所有汽车的状态,但是这个接口又比较耗时

笔者最近就遇到了这样一个业务场景,由于接口查询比较耗时,所以遇到了很多异步导致的问题

在线 Demo

老规矩,先上体验 Demo

codepen.io/firstblood9...

模拟业务代码结构

js 复制代码
// 模拟后端接口
const getStauts = ()=>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve([1,2,3])
    },10000 * Math.random())
  })
}
setInterval(()={
    this.getStatus()
},5000)

也就是 我们每隔 5000ms 会去定时请求这个接口

这马上遇到了一个问题,假设我们接口的响应时间一直是 100000ms

那么我们就会在前10s内发出两个请求

当然更为致命的问题是由于异步响应,导致我们在视图上看到的可能是上一次接口返回的数据

优化代码逻辑

此刻我们可以设置一个 setTimeout 来等待接口完成时再做定时请求

js 复制代码
const run = ()=>{
    this.getStatus().finally(()=>{
        setTimeout(run,5000)
    })
}

此时此刻,已经完全能满足业务需求,但是一点都不通用

彦祖们应该不会满足于此吧?

利用 scheduler 封装通用函数

在开始之前,让我们先来了解下 scheduler 是个什么东西?

  • Scheduler

developer.mozilla.org/en-US/docs/...

  • postTask

developer.mozilla.org/en-US/docs/...

巴拉巴拉一大堆,直接看他咋用就完事了...

大致意思是接收两个参数,第一个是执行函数,第二个是配置参数

  • 配置函数

彦祖们,直接答疑解惑

segmentfault.com/q/101000004...

开始设计函数

其实我们接收到的功能核心 只有两个东西

  1. 执行函数
  2. 执行函数对应的延迟时间

那么我们大致就能写出以下代码

js 复制代码
function run(executor,delay){
    executor().finally(()=>{
        setTimeout(()=>{
            run(executor,delay) // 这里遇到了 this 指向问题
        },delay)
    })
}

到此为止,我们似乎还没用到 scheduler 彦祖们 别急,接着往下看

如何取消对应任务?

某些特殊场景下 我们可能需要取消这个轮询函数

此时 scheduler 以及它的第二个参数 options.signal 该上场了

官方也是巴拉巴拉一大堆,大致意思就是给我传递一个信号指令,我能帮你取消这个任务

此时又引出了另外一个 controller : TaskController

developer.mozilla.org/en-US/docs/...

这玩意继承自 AbortController

完整的通用函数

话不多说 直接上代码

js 复制代码
function run(executor,delay){
    const  abortController = new TaskController()
    scheduler.postTask(()=>{
        executor().finally(()=>{
            setTimeout(run.bind(this),delay) // 修复上面的 this 指向问题
        })
    }, {
      signal: abortController.signal
    })
    return abortController.abort // 返回一个取消函数,这也是一个常用的技巧
}

const cancel = run(getStatus,5000) // 调用 cancel 可以取消任务

彦祖们会发现 line:5 这里遇到了 this指向问题

这是面试八股文遇不到的,程序猿还是要实战啊~

至此 一个完整的通用函数就算封装完成了,代码非常简单

利用 scheduler 封装通用类

其实函数的功能还是有限,比如说用户想在 getStatus 成功后执行 then 逻辑,失败后执行 catch 逻辑

我们希望是这么调用的(catch 是关键字,统一改成 _ 开头)

js 复制代码
const ins = new RecursiveExecutor(getStauts,{
  _then(res){
    console.log('__SY__🍦 ~ then ~ res:', res) // 执行对应的 then 逻辑
  },
  _catch(res){
    console.warn('__SY__🍦 ~ res:', res) // 执行对应的 catch 逻辑
  },
  delay:1000 // 延迟执行时间
})

彦祖们,结构已经出来了 实现就非常简单了,直接上代码

js 复制代码
class RecursiveExecutor{
  constructor(executor,options){
    this.executor = executor
    this.options = options
    this.abortController = new TaskController()
  }
  run(){
    const {_then,_catch,delay} = this.options
    const {executor,abortController,run} = this
    scheduler.postTask(()=>{
      executor().then(_then).catch(_catch).finally(()=>{
        setTimeout(run.bind(this),delay)
      })
    }, {
      signal: abortController.signal
    });
  }
  cancel(){
    this.abortController.abort();
  }
}

当然这只是抛砖引玉,彦祖们 可以自行拓展更多功能~

写在最后

业务项目中,类似的业务场景是非常多见的

但是要考虑抽象成一个公共的底层功能,这是非常考验我们 抽象和编程能力的

说归说, 其实最后还是 cv 最香,要什么自行车么😚

个人能力有限

如有不对,欢迎指正 🌟 如有帮助,建议小心心大拇指三连🌟

相关推荐
懒大王爱吃狼25 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
待磨的钝刨1 小时前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
逐·風4 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫5 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦5 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子6 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山6 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享7 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
从兄7 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
清灵xmf9 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询