函数节流和防抖

引言:bash

在咱们的开发过程当中都会遇到高频事件,好比说onscroll事件,每当页面滚动的时候,每一秒可能会触发几十次的函数执行, 假如onscroll还绑定了回调函数,并对dom进行重排,那么每一秒执行几十次dom渲染,若是dom操做过多,那么页面可能会出现卡顿的现象。app

或者resize行为每一次页面窗口的变化都会绑定dom的渲染也会出现上述状况。为了优化高频事件(oninput,onkeyup,onkeydown),下降代码执行频率,采用优化方案函数的回流和防抖。dom

函数节流 (throttle)

函数在必定时间内执行一次核心代码。好比人在一段时间眨一次眼睛。函数

let btn = document.getElementById('btn')

        function logger() {
            console.log('logger') // 每一秒打印一次
        }

        function throttle(func, wait) {
            let previous = 0
            return function() {
                let now = Date.now()
                if (now - previous > wait) {
                    func.apply(this, arguments)
                    previous = now
                }
            }
        }
        btn.addEventListener('click', throttle(logger, 1000))
复制代码

logger函数用来测试,正常每次点击都会打印'logger', 节流处理每一秒打印一次'logger'测试

previous 相对于上一次点击的时间 now 每次点击记录的事件优化

now - previous > wait 第一次由于previous 为 0 第一次执行 logger函数, 把previous 赋值为当前时间ui

第二次的时候只有当前时间和上次时间大于 wait(1000毫秒)的时候才会再次执行loggerthis

对throttle函数优化

用户最后一次的点击事件触发无论是否小于wait这里是1s咱们须要记录下来,触发一次loggerspa

function throttle(func, wait, options) {
            let previous = 0
            let timer;
            let me = this;
            let later = function() {
                previous = Date.now()
                func.apply(me, arguments)
            }
            let throttled = function() {
                let now = Date.now();
                let remaining = wait - (now - previous); 
                if (remaining <= 0) {  // 小于0 说明点击事件间隔大于1000ms
                    if (timer) {
                        clearTimeout(timer)
                        timer = null
                    }
                    func.apply(me, arguments)
                    previous = now
                } else if (!timer && options.trailing) {
                    timer = setTimeout(later, remaining)
                }
            }
            return throttled
        }
        btn.addEventListener('click', throttle(logger, 1000, { trailing: true}))
复制代码

trailing等于 true开启模式code

点击事件时间间隔越短并小于1s ,now-previous值越小, 那么 wait - (now - previous)值必定大于0 remaining > 0

第一次click !timer && options.trailing 成立, 结束后多执行一次later

下一次 先清除timer 再进入判断 执行下一次later

函数防抖 (debounce)

函数在执行完毕的时候,才触发核心代码执行, 好比在作电梯的时候,若是关门的过程当中,有人要上来,不会走,等他上来一块走。

function logger() {
      console.log('logger')
  }
  function debounce(func, wait) {
      let timeout;
      return function() {
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            func.apply(this, arguments)
             timeout = null
        }, wait)
      }
  }
  btn.addEventListener('click', debounce(logger, 1000))
复制代码

每次高频率click的时候都会清除上一次的定时器不会执行代码, 只有等到松开1s后才会执行代码

函数防抖优化

每次第一次点击的时候先执行一次

function logger() {
      console.log('logger')
  }
  function debounce(func, wait, immediate) {
    let timeout;
      return function() {
        clearTimeout(timeout)
        if(immediate) {
            let callNow = !timeout
            if(callNow) func.apply(this, arguments)
        }
        timeout = setTimeout(() => {
            func.apply(this, arguments)
            timeout = null
        }, wait)
      }
  }
  btn.addEventListener('click', debounce(logger, 1000, true))
复制代码

参考资料

underscore