likes
comments
collection
share

什么,你还不会使用异步条件函数?

作者站长头像
站长
· 阅读数 19

前言

在我们项目开发中,经常会遇到当满足 xx 条件的时候,才去执行 xx 函数

其实最简单的方式就是利用回调函数

但是这样做业务耦合性太强, 接下来 让我们一步步来实现一个通用异步条件函数

业务场景模拟

不知道 大家最近股市收益如何? 接下来让我们来模拟茅台股的购买

假设你是一位股民,此时账户金额为 0, 每 20ms 账户金额会增加 100

今天的茅台股价为 10000

常规业务代码

const user = {
  name: 'user1',
  account: 0
}
user.buy = function(stock,price) {
  if(user.account<price) return console.log(`余额${user.account}不足,不能购买${stock}`)
  console.log(`我的账户金额达到了 ${user.account},此时可以购买${stock}了`)
}

/*
模拟后台行为
每 20ms 账户金额自动增加100
达到 10000 的时候可以购买茅台
*/
const accountGrow = () => {
  setInterval(() => {
    user.account += 100
  }, 20)
}
accountGrow()
/* 模拟后台行为end */

const fn = () => {
  if (user.account>=10000) {
    user.buy('茅台',10000)
  } else {
    setTimeout(fn, 200)
  }
}
fn()

以上就是我们的常规思路,利用不断轮询判断某个异步条件是否成立

通用函数设计

简单记录下自己的设计思路吧,其实无非就是三个参数

  1. 异步执行函数
  2. 异步条件函数
  3. 轮询的时间参数

有了这三个条件,我们设计的函数签名如下

const fn = (asyncExecutor,asyncCondition,delay)=>{}

进一步解耦

一开始笔者设计的是没有 return 值的,也就是直接把业务代码在 fn 中执行了

这样的做法就导致耦合性非常高,并且 不好进行参数的传递

借鉴 debounce 防抖的思想,最终决定 return 一个函数出去, 大致结构如下

const fn = (asyncExecutor,asyncCondition,delay)=>{
    if(asyncCondition()){
        return function(...args){
            return asyncExecutor(...args)
        }
    }
}

但是condition的代码需要不断轮询,直接 return 函数并没有什么软用

所以此时又借助了promise

完整代码

其实函数设计思路有了,写代码 对各位彦祖来说,就是小意思了

const getAsyncExecutor = (asyncExecutor, asyncCondition, options={delay:10,timeout:10 * 1000}) => {
  if (typeof asyncExecutor !== 'function') return console.warn(`asyncExecutor must be function,but get ${typeof asyncExecutor}`)
  if (typeof asyncCondition !== 'function') return console.warn(`asyncCondition must be function,but get ${typeof asyncCondition}`)

  const {delay,timeout} = options
  const start = performance.now()
  let timer = null

  return new Promise((resolve, reject) => {
    const loop = function(asyncExecutor, asyncCondition, delay) {
      if (performance.now() - start > timeout) {
        // 超时了
        if (timer) clearTimeout(timer)
        return reject(`调用超时了`)
      }
      const finished = asyncCondition.apply(this)
      if (finished) {
        if (timer) clearTimeout(timer)
        const res = function(...args) {
          return asyncExecutor.apply(this, args)
        }
        resolve(res)
      } else {
        timer = setTimeout(() => {
          loop.call(this, asyncExecutor, asyncCondition, delay)
        }, delay)
      }
    }
    loop.call(this, asyncExecutor, asyncCondition, delay)
  })
}

下面让我们用封装代码简单测试一下刚才的场景

/*
模拟后台行为
每 20ms 账户金额自动增加100
达到 10000 的时候可以购买茅台
*/
const user = {
  name: 'user1',
  account: 0
}
user.buy = function(stock,price) {
  if(user.account<price) return console.log(`余额${user.account}不足,不能购买${stock}`)
  console.log(`我的账户金额达到了 ${user.account},此时可以购买${stock}了`)
}
const accountGrow = () => {
  setInterval(() => {
    user.account += 100
  }, 20)
}
accountGrow()
/* 模拟后台行为end */

const executor = (data) => {
  console.log('🚀 ~ executor ~ data:', data)
  user.buy('茅台',10000)
}
const condition = () => user.account >= 10000
// 返回一个 promise 我们需要 借助 async await,或者.then
getAsyncExecutor(executor, condition).then(asyncExecutor=>{
  asyncExecutor('终于能买茅台了')
})

写在最后

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

彩蛋

宁波团队还有一个hc, 带你海鲜自助。 欢迎彦祖们私信😚

转载自:https://juejin.cn/post/7270831230076239930
评论
请登录