JS中的节流和防抖(重要)

470 阅读3分钟

Description

前置

大家好,我又来了,今天我们说一下,JavaScript中的防抖和节流,防抖和节流是前端最基础的优化,在面试中,面试官也是经常问到的,我们马上开始

开始

什么是防抖? 防抖:是一个频发的函数,在规定的时间内,只能让函数只能执行一次

防抖的应用场景有哪些呀?

  • 用户输入搜索框的时候,为了避免多次敲击键盘,而每次都会发生获取数据

如下代码:

function depagect(func,times){
    //定义一个标识符
    var timer
    return function(){
        //清空定时器
       clearTimeout(timer)
       //获取原生event参数
       var event=arguments[0]
        //创建定时器
      timer = setTimeout(function(){
          func(event)
      },times)
    }
}
$('.input').on('keyup', debounce(handle, 1000))
  • 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位
  • 文本编辑器实时保存,当无任何更改操作一秒后进行保存

防抖的类型分为?

  • 立即执行版本 立即执行版的意思是触发事件后函数会立即执行,然后 n 秒内不触发事件才能继续执行函数的效果。 代码如下:

/**
 * @description: 
 * @param {*} func 触发的事件
 * @param {*} wait 多少时长才执行事件
 * @return {*}
 */

function debounce(func,times){
    //定义一个标识符
    let timeout
    //返回一个函数
    return function(){
        //定义当前的this
        const ontext = this
        //获取原生event参数
        const args = [...arguments]
        //判断如果是timeout,就清除定时器
        if(timeout) clearTimeout(timeout);
        //取反
        const callNow=!timeout
        timeout=setTimeout(()=>{
            timeout=null
        },times)
        //如果是callNow,就把func应用到context,并追加args
        if(callNow) func.apply(context,args)
    }
}
$('.input').on('keyup', debounce(handle, 1000))
  • 非立即执行版本 非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

代码如下

function debounce(func, wait) {
  let timeout;
  return function(){
      // 获取当前作用域和参数
      const context = this;
      const args = [...arguments] 
      // 如果当前timeout 存在
      // 清空定时器,再次等待wait时间过后再次执行事件
      if(timeout) clearTimeout(timeout)
      // 定时执行 传递进来的事件
      timeout = setTimeout(()=>{
         func.apply(context,args)
      },wait)  
  }
}
$('.input').on('keyup', debounce(handle, 1000))
  • 合成版本 通过传递  Boolean 来决定执行哪种版本。

  • true 为立即执行版

  • false 为非立即执行版本

debounce(func,1000,true) 代码如下

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func, wait, immediate) {
  let timeout;
  return function () {
    const context = this;
    const args = [...arguments];
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      const callNow = !timeout;
      timeout = setTimeout(() => {
        timeout = null;
      }, wait)
      if (callNow) func.apply(context, args)
    }
    else {
      timeout = setTimeout(() => {
        func.apply(context, args)
      }, wait);
    }
  }
}

节流

什么是节流?

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。  节流会稀释函数的执行频率。

节流应用场景有哪些?

  1. scroll 事件,每隔一秒计算一次位置信息等
  2. 浏览器播放事件,每个一秒计算一次进度信息等
  3. input 输入框在搜索内容时,可以控制多少s 在执行请求,避免多次发起请求,节约性能。

节流有两种实现

  1. 时间戳版本
function throttle(func, wait) {
    var previous = 0;
    return function() {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > wait) {
            func.apply(context, args);
            previous = now;
        }
    }
}
  1. 定时器版本
function throttle(func, wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => {
                timeout = null;
                func.apply(context, args)
            }, wait)
        }

    }
}

代码解析

当执行  throttle 函数时,timeout 默认为 undefined , 此时, ! timeout 为  true 时,执行 定时器,并且 将  timeout 为 null,即为 false, 再次执行 throttle 函数时, !timeout 又为  true ,再次执行定时器。

通过  timeout 的状态来达到节流的控制

总结

  • 防抖: 触发事件后,一定时间后再执行事件,可以 立即执行 也可以 一定时间再执行

  • 节流: 控制流量,在单位时间内只能请求一次,避免多次触发事件,影响服务器性能。