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 最香,要什么自行车么😚

个人能力有限

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

相关推荐
brief of gali5 分钟前
记录一个奇怪的前端布局现象
前端
前端拾光者43 分钟前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
Json_181790144801 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网1 小时前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子02041 小时前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing1 小时前
React核心功能详解(一)
前端·react.js·前端框架
捂月2 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆2 小时前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China2 小时前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q2 小时前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge