封装一个同事直呼好用的异步条件函数

前言

彦祖们,在我们日常开发中经常会遇到这样一个场景

轮询某个异步条件是否满足,如果满足再去执行某个函数

业务场景复现

笔者现在模拟一个业务场景

有一个叫马宝的大师,他的技能有 vue react node 闪电五连鞭,他目前的等级是1

js 复制代码
const user = {
    name:'马宝',
    skill:['vue','react','node','闪电五连鞭'],
    level:1
}

随着时间的推移,马宝闪电五连鞭技能在不断增长,他的等级也在不断提升

level 达到 100 的时候将会获得一个称谓 浑元形意太极拳掌门人

模拟服务端逻辑

彦祖们,这段逻辑主要是模拟了真实的业务逻辑,假设每过 10ms level+1

js 复制代码
const serverLogic = setInterval(()=>{
    user.level++
},10)

业务功能实现

常规写法

我们需要用一个轮询器去监听马宝是不是达到了 100 级

如果达到了,我们就去给他加上一个称谓,直接上代码

js 复制代码
const frontLogic = setInterval(()=>{
    if(user.level >= 100){
      clearInterval(frontLogic)
      clearInterval(serverLogic)
      user.title = '浑元形意太极拳掌门人'
    }
    console.log(user)
},10)

看下打印,符合我们的预期

抽象逻辑

这种写法很不通用

假设在开发中有多个这样的场景,彦祖们就需要写很多个轮询器去监听,代码就会变得臃肿

那么针对这种异步条件的监听,我们有没有更好的方式呢?

其实分析一下我们的这个业务场景,可以发现,我们的这个业务场景有两个条件

  1. 马宝的等级是否达到了 100级(异步执行条件 condition)
  2. 马宝的等级达到了 100级 之后,给他加上一个称谓(异步执行函数 executor)

函数封装

此时我们就可以抽象出一个函数

这个函数接收两个参数

第一个参数是一个异步条件 condition

第二个参数是一个执行函数 executor

来看下我们此时的函数签名

js 复制代码
const asyncCondition = (condition,executor) => {
    if(condition()) executor()
}

场景是异步的,我们开启用一个轮询器去监听

把这个函数改造一下,并且返回一个 Promise

js 复制代码
const asyncCondition = (condition,executor) => {
    return new Promise((resolve,reject)=>{
      const timer = setInterval(()=>{
        if(condition()){
          clearInterval(timer)
          executor()
          resolve()
        }
      },10)
    })
}

彦祖们,看下此时的调用方式

js 复制代码
const condition = () => {
    return user.level >= 100
}
const executor = () => {
    user.title = '浑元形意太极拳掌门人'
    console.log('__SY__🎄 ~ executor ~ user:', user)
}
asyncCondition(condition,executor)

看下打印,没有问题,此时一个最基础的版本算是完成了

函数优化

不过对于以上函数我们还有很多需要优化的,比如

  1. 新增轮询的时间间隔参数
  2. 新增异步操作的超时时间参数,如果超过了这个时间,我们就直接 reject
  3. 新增对函数的参数校验
  4. 新增 try catch 来捕获异常情况

接下来让我们继续来完善,其实方向明确了,代码就非常简单了 直接上代码吧

js 复制代码
const asyncCondition = (condition,executor,options = { interval: 1, timeout: 10 * 1000 }) => {
  if (typeof condition !== 'function')  throw new TypeError(`asyncCondition'condition must be function,but get ${typeof condition}`)
  if (typeof executor !== 'function')  throw new TypeError(`asyncCondition'executor must be function,but get ${typeof executor}`)
    const { interval,timeout } = options
    const start = performance.now() // 记录开始时间
    return new Promise((resolve,reject)=>{
      const timer = setInterval(()=>{
        // 判断是否超时
        if(performance.now() - start > timeout){
          clearInterval(timer)
          reject(new Error('asyncCondition timeout'))
          return
        }
        try{
          if(condition()){
            clearInterval(timer)
            executor()
            resolve()
          }
        }catch(e){
          clearInterval(timer)
          reject(e)
        }
      },interval)
    })
}

到此为此,函数已经比较完善了

我们可以用这个函数来解决很多异步条件的监听问题

但是笔者认为这种调用方式还是有点累赘,既然返回了一个 Promise,就没必要再传入 executor

彦祖们,看下这行代码

js 复制代码
asyncCondition(condition).then(()=>{
    executor()
})

是不是亲切多了?这种形式就更加简洁,也更符合我们日常的编程习惯

到这一步应该已经非常简单了,直接上完整版代码

完整代码

js 复制代码
const asyncCondition1 = (condition,options = { interval: 1, timeout: 10 * 1000 }) => {
    if (typeof condition !== 'function')  throw new TypeError(`asyncCondition'condition must be function,but get ${typeof condition}`)
    const { interval,timeout } = options
    const start = performance.now() // 记录开始时间
    return new Promise((resolve,reject)=>{
      const timer = setInterval(()=>{
        // 判断超时
        if(performance.now() - start > timeout){
          clearInterval(timer)
          reject(new Error('asyncCondition timeout'))
          return
        }
        try{
          if(condition()){
            clearInterval(timer)
            resolve()
          }
        }catch(e){
          clearInterval(timer)
          reject(e)
        }
      },interval)
    })
}

测试下

js 复制代码
asyncCondition(condition).then(executor)

再测试下异常情况

js 复制代码
asyncCondition(()=>{
    throw new Error('执行过程报错了')
}).then(executor).catch(e=>{
    console.log('__SY__🎄 ~ e:', e)
})

同样非常完美,到此为止一个通用的异步条件监听函数就诞生了

同事直呼好家伙,这个函数真的好用🥳

写在最后

代码虽然不多也非常简单,但是在日常工作中,需要抽象出这些公共逻辑

是非常考验彦祖们的开发能力的

个人能力有限

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

相关推荐
速盾cdn30 分钟前
速盾:网页游戏部署高防服务器有什么优势?
服务器·前端·web安全
小白求学132 分钟前
CSS浮动
前端·css·css3
什么鬼昵称33 分钟前
Pikachu-csrf-CSRF(POST)
前端·csrf
golitter.1 小时前
Vue组件库Element-ui
前端·vue.js·ui
儒雅的烤地瓜1 小时前
JS | JS中判断数组的6种方法,你知道几个?
javascript·instanceof·判断数组·数组方法·isarray·isprototypeof
道爷我悟了1 小时前
Vue入门-指令学习-v-on
javascript·vue.js·学习
27669582921 小时前
京东e卡滑块 分析
java·javascript·python·node.js·go·滑块·京东
golitter.1 小时前
Ajax和axios简单用法
前端·ajax·okhttp
PleaSure乐事1 小时前
【Node.js】内置模块FileSystem的保姆级入门讲解
javascript·node.js·es6·filesystem
雷特IT2 小时前
Uncaught TypeError: 0 is not a function的解决方法
前端·javascript