前端优化-防抖&节流

我发布了一个工具包,包括了防抖,节流,懒加载等工具函数。可以在 JS 和 TS 项目中使用 : https://www.npmjs.com/package/utils-h
GitHub :https://github.com/wtdsn/utils-h#readme

什么是防抖

顾名思义,就是防止抖动的。比如验证码点击切换,用户快速点击了5次,但其实不用切换五次验证码,只需要切换一次就行了。那么就可以使用防抖。

防抖的特点是一定时间内的连续多次的触发,只会执行一次真正的回调。

防抖的作用

节省资源,节省前端资源,提高性能;
如果要发起请求,还可以节省网络资源,降低服务器压力

什么是节流

节流是限制触发的频率,比如连续的滚动,scroll事件会被频繁的触发。如果这个时候,需要通过JS 去操作 DOM ,那么频繁的操作就会降低性能,导致页面卡顿
这个时候,就可能需要使用节流,限制它 16 ms 执行一次,如果不需要太及时,30ms执行一次也可以

节流的特点就是用户连续,频繁的触发某一事件时,真正的回调会以一定的频率进行执行。但总的次数比原本不节流的次数要少

节流的作用

节省资源,节省前端资源,提高性能;
如果要发起请求,还可以节省网络资源,降低服务器压力

其实和防抖一样,使用场景不同罢了

区别

防抖和节流的区别:

防抖是在连续,多次的执行某个动作时,只真正的响应一次。它限制了响应的次数。

节流是在连续,多次的执行某个动作时,限制了响应的频率。

假如我们10s内连续,快速地触发某个事件,防抖只会触发一次,而节流会按照一定的频率触发多次

从使用场景来看,比如一个搜索按钮,用户连续点击多次,只需要执行一次就可以了。但是如果是 resize 时,我们希望内容的宽高也能够及时的更改去适应 resize 的变化,那么就需要使用节流

使用场景

防抖:

  • 点击某个按钮,比如查询,搜索
  • 切换验证码
  • 自动保存用户编辑的内容时
  • Resize 变化时
  • 对用户输入的内容进行模糊匹配时

节流:

  • Resize 变化时
  • 对用户输入的内容进行模糊匹配时
  • Scroll 页面懒加载

有些场景 ,防抖和节流都可以使用,看实际的效果需求!

实现

主要的原理是利用闭包:对实际的回调函数进行封装,返回一个新的函数,利用闭包缓存的变量,控制回调是否执行

防抖

  • 简单版防抖函数

主要实现思路是设置一个定时器,如果在等待时间内重新触发,则取消定时器,重新计时

/** 
 * @param {any} wait 
 * @param {any} fun 
 */
function debounce_simple(wait, fun) {
  let timer
  // 注意点1:,这里不能用箭头函数,因为箭头函数的 this 是函数设置的位置。于调用无关
  // 并且无法使用 bind ,call 等
  return function () {
    clearTimeout(timer)
    // 注意点2:这里需要使用箭头函数,this 使用这里的 this 和 arguments。
    // 如果不是箭头函数,需要先把 this 和 arguments 缓存到其他变量使用
    timer = setTimeout(() => {
      fun.call(this, arguments)
    }, wait)
  }
}

  • 复杂版

基于简单版本,增加 immediate 参数,即第一次调用立即执行

/**
 * @param {any} wait  等待时间
 * @param {any} fun   回调函数
 * @param {any} immediate  是否立即执行
 * @returns {function} 返回一个新的函数
 */
function debounce(wait, fun, immediate = false) {
  // 定时器
  let timer = null
  // 是否取消
  let waiting = false

  return function () {
    // 等待中
    if (waiting) {
      clearTimeout(timer)
      if (immediate) {
        timer = setTimeout(() => {
          waiting = false
        }, wait)
      } else {
        timer = setTimeout(() => {
          waiting = false
          fun.apply(this, arguments)
        }, wait)
      }
      return
    }
    waiting = true
    // 立即执行
    if (immediate) {
      fun.apply(this, arguments)
      timer = setTimeout(() => {
        waiting = false
      }, wait)
    } else {
      // 非立即执行
      timer = setTimeout(() => {
        waiting = false
        fun.apply(this, arguments)
      }, wait)
    }
  }
}

节流

  • 简单版节流
    利用定时器
/**
 * @param {any} dur 
 * @param {any} fun 
 * @return 
 */
function throttle_simple(dur, fun) {
  let waiting = false

  return function () {
    if (waiting) return
    waiting = true
    fun.call(this.arguments)
    setTimeout(() => {
      waiting = false
    }, dur)
  }
}
  • 简单版节流
    利用时间戳
function throttle_simple2(dur, fun) {
  let pre = 0

  return function () {
    let cur = Date.now()
    if (cur - pre >= dur) {
      fun.call(this.arguments)
      pre = cur
    }
  }
}
  • 复杂版

节流复杂版,增加 endCall 参数,表示在末尾是否重新调用。
比如用户改变屏幕大小,需要调节元素,最后移动了 100px ,却刚好在等待时间内。导致元素没有及时调节

function throttle(dur, fun, endCall = true) {
  let pre = timer = 0

  return function () {
    let cur = Date.now()
    if (cur - pre >= dur) {
      if (endCall) {
        clearTimeout(timer)
        timer = 0
      }

      fun.call(this.arguments)
      pre = cur

      return
    }
    if (endCall && !timer) {
      timer = setTimeout(() => {
        fun.call(this.arguments)
        pre = cur
        timer = 0
      }, dur)
    }
  }
}

你可能感兴趣的:(前端优化,前端,javascript,性能优化,面试)