js实现一个setTimeout模拟setInterval的类管理工具

205 阅读1分钟

isFunction 可以看这篇文章 js判断参数类型的实用工具

import { isFunction } from '@utils/util.type'

class SetInterval {
  private tasks = new Map()

  /**
   * @description: 添加定时器方法
   * @param {any} name
   * @param {async function} callback 必须是异步函数
   * @param {number} wait 等待时间 默认一秒
   * @param {boolean} leading 是否先执行一次
   * @return {undefined}
   */
  add = (name: string, callback: Function, wait: number = 1000, leading: boolean = false) => {
    if (!name) {
      console.error('Setinterval => add => 必须传入name')
      return
    }

    if (this.tasks.has(name)) {
      console.error(`Setinterval => add => 已有相同name名字定时器, 请更换name名 => ${name}`)
      return
    }

    if (!isFunction(callback)) {
      console.error('Setinterval => add => callback必须为一个函数')
      return
    }

    console.log(`%c添加定时器[${name}]成功, 刷新间隔为[${wait}]毫秒, ${leading ? '已' : '未'}开启先执行一次callback功能`, 'color: #24c59d; font-weight: 700')
    this.tasks.set(name, { wait, callback, leading })

    this.run(name)
  }

  /**
   * @description: 将定时任务添加到队列中
   * @param {string} name 定时器名称
   * @return {*}
   */
  run = (name: string) => {
    const inner = () => {
      const task = this.tasks.get(name)
      if (task) {
        this[name] = setTimeout(async () => {
          try {
            await task.callback()
          } catch (error) {
            console.error(`SetInterval => run => inner => 定时器 [${name}] 执行出错, 错误原因 => ${error}`)
          } finally {
            task.leading = false
            this.closeTimeout(name)
            inner()
          }
        }, task.leading ? 0 : task.wait)
      }
    }
    inner()
  }

  /**
   * @description: 关闭某个定时器
   * @param {string} name 定时器名称
   * @return {*}
   */
  closeTimeout = (name: string) => {
    clearTimeout(this[name])
    this[name] = null
  }

  close = (name: string) => {
    try {
      const task = this.tasks.get(name)

      if (task) {
        this.tasks.delete(name)
        this.closeTimeout(name)
        console.log(`%c关闭定时器[${name}]成功`, 'color: #24c59d; font-weight: 700')
      } else {
        console.error(`SetInterval => close => 未找到 [${name}] 定时器`)
      }
    } catch (error) {
      console.error('SetInterval => close => 删除task失败 => 失败原因 => ', error)
    }
  }
}

export default new SetInterval()