Skip to content

💤

随机[a, b]的整数

typescript
/**
 * 随机[a, b]的整数
 * @param a
 * @param b
 */
function randomInt(a: number, b: number): number {
  return Math.floor(Math.random() * (b + 1 - a)) + a
}

防抖

typescript
/**
 * 防抖
 * @param fn
 * @param delay
 */

function debounce(fn: Function, delay: number) {
  let timer: any = null
  return function (...args: any) {
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      fn.apply(this, args)
      timer = null
    }, delay)
  }
}

防抖-首次立即执行

typescript
/**
 * 防抖-首次立即执行
 * @param fn
 * @param delay
 */
function debounce(fn: Function, delay: number) {
  let timer: any = null
  return function (...args: any) {
    let callNow = !timer
    if (timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(() => {
      timer = null
    }, delay)
    if (callNow) {
      fn.apply(this, args)
    }
  }
}

promise

javascript
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class ZPromise {
  #status = PENDING
  #value = undefined
  #queue = []

  constructor(executor) {
    const resolve = data => {
      this.#changeStatus(FULFILLED, data)
    }
    const reject = reason => {
      this.#changeStatus(REJECTED, reason)
    }
    try {
      executor(resolve, reject)
    } catch (e) {
      reject(e)
    }
  }

  #changeStatus(status, data) {
    if (this.#status !== PENDING) return
    this.#status = status
    this.#value = data
    this.#runTaskQueue()
  }

  ##resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
      return reject(new TypeError('Chaining cycle detected for promise'))
    }
    if (x instanceof ZPromise) {
      x.then(resolve, reject)
    } else {
      resolve(x)
    }
  }

  #runTask(cb, resolve, reject, promise2) {
    this.#runMicroTask(() => {
      if (typeof cb !== 'function') {
        resolve(this.#value)
        return
      }
      try {
        const x = fn(this.#value)
        this.#resolvePromise(promise2, x, resolve, reject)
      } catch (e) {
        reject(e)
      }
    })
  }

  #runTaskQueue() {
    if (this.#status === PENDING) return
    const { onFulfilled, onRejected, resolve, reject, promise2 } = this.queue.shift()
    while (this.#queue.length) {
      this.#runTask(this.#status === FULFILLED ? onFulfilled : onRejected, resolve, reject, promise2)
    }
  }

  then(onFulfilled, onRejected) {
    const promise2 = new ZPromise((resolve, reject) => {
      this.#runMicroTask(() => {
        this.queue.push({
          onFulfilled,
          onRejected,
          resolve,
          reject,
          promise2,
        })
        this.#runTaskQueue()
      })
    })
    return promise2
  }

  // utils
  #runMicroTask(fn) {
    if (typeof queueMicrotask === 'function') {
      queueMicrotask(fn)
    } else if (typeof process === 'object' && process.nextTick) {
      process.nextTick(fn)
    } else if (typeof MutationObserver === 'function') {
      const observer = new MutationObserver(fn)
      const textNode = document.createTextNode('')
      observer.observe(textNode, { characterData: true })
      textNode.data = '1'
      observer.disconnect()
    } else {
      setTimeout(fn, 0)
    }
  }
}