Write it up front

Search articles or columns of handwritten anti-shake functions on major network platforms. Some do not specifically implement the functions of leading and trailing, and some do but lack detailed thinking flow.

Today happens to review the throttling function handwriting, also should remind myself to write an article to record.

Implement processes and functions

  1. Basic implementation of throttle (leading=true,trailing=false)

  2. leading = false, trailing = true ; The functions leading = true and trailing = false are implemented

  3. Problems with the this binding and arguments

  4. Cancel the implementation of the function

  5. Return value problem

added

Q: Why not implement false for both leading and trailing?

A: If both values are false, the user enters the input once and waits for the result, but no output is generated

And the throttle function discovery that references the underscore encapsulation does not implement this functionality either

Basic implementation of the throttle function

function throttle(fn, interval) {
  let lastTime = 0
  const _throttle = function () {
    const nowTime = new Date().getTime()
    const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      fn()
      lastTime = nowTime
    }
  }
  return _throttle
}
Copy the code

Implementation approach

  1. The _throttle function is called when it is actually executed, so throttle returns a _throttle function.

  2. The _throttle function is called to record the nowTime value every time, and compare the calculated remainTime with delay. When the remainTime value is less than or equal to delay, it means that a cycle has passed, and then the FN function is executed once.

  3. Set the value of lastTime to nowTime, the next call will restart the calculation of remainTime to compare with delay, equivalent to another new cycle.

  4. Note: When first clicked, since lastTime is 0 and new Date().getTime() must get a large number, the fn function is executed immediately.

Leading = false, trailing = true and leading = true, trailing = false are implemented

function throttle(fn, interval, options = { leading: true, trailing: false }) {
  let lastTime = 0
  const { leading, trailing } = options
  let timer = null

  const _throttle = function () {
    const nowTime = new Date().getTime()

    / / processing leading
    if(! leading && ! lastTime) { lastTime = nowTime }const remainTime = interval - (nowTime - lastTime)

    // the fn function executes
    if (remainTime <= 0) {
      // Enter when remainTime is exactly 0
      // Since mainScript will execute first, the timer can be cancelled and the callback will not execute
      // If the value is not exactly 0, the callback function will be executed, and the fn function will be executed twice
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      fn()
      lastTime = nowTime
      // If you do not return, the timer will be added
      return
    }

    / / handle the trailing
    if(trailing && ! timer) { timer =setTimeout(() = > {
        timer = null
        // If leading is false,lastTime = 0
        // If leading is true,lastTime = nowTimelastTime = ! leading ?0 : new Date().getTime()
        fn()
      }, remainTime)
    }
  }
  return _throttle
}
Copy the code

Implementation approach

  • When leading is false:

    To wait for an interval in the beginning, set lastTime to nowTime.

    If lastTime is set by leading alone, then _throttle sets lastTime to nowTime each time and waits for interval.

    When the value of lastTime is 0, it means that the throttling function is called for the first time and lastTime is set to nowTime to wait for interval

  • leading=false,trailing=true

    If leading is set to false, the function will be called once after interval, so timers can be used:

    • When trailing is false, a timer is started, and when the user does not enter during this time, the callback in setTimeout is automatically executed, which executes the FN function and sets the timer back to NULL.

      The value of lastTime is set by leading:

      When leading is false, set lastTime to 0, so that when the user does not enter for a long time, the next input will return to if (! Leading && lastTime) {lastTime = nowTime};

      When leading is true, set lastTime to the current time. When the user does not enter nowTime after a long period of time, it is still much larger than lastTime, so leading is true.

    • When the timer is turned on, the user still has input:

      RemainTime > 0

      At this point, you should continue the previous timer, so if (trailing &&! The timer) judgment

      Case 2: remainTime = 0

      Now the code in if (remainTime <= 0) will be executed, that is, the FN function will be executed, but at this time the timer will end, because the setTimeout callback is in the macro queue later than the mainScript code, so the timer should be cleared, Set timer back to NULL and return to prevent starting the timer again.

  • leading=true,trailing=true

    It’s already done! Before lastTime =! leading ? 0: new Date().getTime()

Problems with the this binding and arguments

No problem as long as you know this

function throttle(fn, interval, options = { leading: true, trailing: false }) {
  let lastTime = 0
  let timer = null
  const { leading, trailing } = options

  const _throttle = function (. args) {
    const nowTime = new Date().getTime()
    if(! leading && ! lastTime) { lastTime = nowTime }const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      fn.apply(this, args)
      lastTime = nowTime
      return
    }
    if(trailing && ! timer) { timer =setTimeout(() = > {
        timer = nulllastTime = ! leading ?0 : new Date().getTime()
        fn.apply(this, args)
      }, remainTime)
    }
  }
  return _throttle
}

Copy the code

Cancel the implementation of the function

function throttle(fn, interval, options = { leading: true, trailing: false }) {
  let lastTime = 0
  let timer = null
  const { leading, trailing } = options

  const _throttle = function (. args) {
    const nowTime = new Date().getTime()
    if(! leading && ! lastTime) { lastTime = nowTime }const remainTime = interval - (nowTime - lastTime)
    if (remainTime <= 0) {
      if (timer) {
        clearTimeout(timer)
        timer = null
      }
      fn.apply(this, args)
      lastTime = nowTime
      return
    }
    if(trailing && ! timer) { timer =setTimeout(() = > {
        timer = nulllastTime = ! leading ?0 : new Date().getTime()
        fn.apply(this, args)
      }, remainTime)
    }
  }
  _throttle.cancel = function () {
    if(timer){
      clearTimeout(timer)
    }
    timer = null
    lastTime = 0
  }
  return _throttle
}
Copy the code

Return value problem

Failure to return result directly

When result = fn.apply(this,args) is executed, the assignment of result will be several seconds later and result will still be null after mainScript has finished executing

function throttle(fn, interval, options = { leading: true, trailing: false }) {
  let lastTime = 0
  let timer = null
  const { leading, trailing } = options

  const _throttle = function (. args) {
    return new Promise((resolve) = > {
      const nowTime = new Date().getTime()
      / / processing leading
      if(! leading && ! lastTime) { lastTime = nowTime }// Normal execution
      const remainTime = interval - (nowTime - lastTime)
      if (remainTime <= 0) {
        if (timer) {
          clearTimeout(timer)
          timer = null
        }
        const result = fn.apply(this, args)
        resolve(result)
        lastTime = nowTime
        return
      }
      / / handle the trailing
      if(trailing && ! timer) { timer =setTimeout(() = > {
          timer = null
          const result = fn.apply(this, args) resolve(result) lastTime = ! leading ?0 : new Date().getTime()
        }, remainTime)
      }
    })
  }

  _throttle.cancel = function () {
    if (timer) {
      clearTimeout(timer)
    }
    timer = null
    lastTime = 0
  }

  return _throttle
}
Copy the code

Write in the last

This is my first time to write an article, I hope you can point out in the comments section if there is something wrong

Declined to be reproduced!! Reproduced will investigate!!