防抖和节流

203 阅读5分钟

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

防抖

(一) 什么是防抖

防抖就是触发函数行为之后在一定时间内 只能执行一次,如果在时间内又一次触发,会重新计算函数的执行时间

(二) 防抖的作用

如果一个函数被频繁的触发执行,会消耗大量的内存,影响性能,有可能会造成浏览器卡顿,甚至直接卡死的状况 ,使用防抖处理之后会避免这种情况的出现

(三) 如何实现

可以封装一个防抖的函数,来限制这些函数的触发执行时间 ,防抖可以根据不同业务需求判断是否需要立即执行或非立即执行,该函数接收三个参数,函数,延迟时间,是否立即执行,他会返回一个处理好的新函数

(四) 应用场景

input搜索框的模糊查询,用户在不断输入值的时候,使用防抖可以节约请求资源

文本编辑器实时保存,当无任何操作更改的一秒后进行保存

(五) 代码实现

/**
  @desc 防抖函数
  @param fun 函数
  @param time 延迟时间
  @immediate  是否立即执行
*/

const debounce = (fun,time,immediate) => {
	let timeout; //定义一个变量存储延时器函数返回的id
  return function(){
  	let args = arguments; //获取参数
    let context = this; // 获取this
    if( timeout ) clearTimeout(timeout) //判断条件清除定时器函数
    if( immediate ){  //是否立即执行
    	var callNow = !timeout
      timeout = setTimeout(()=> {
      	timeout = null
      },time)
      if(callNow) fun.apply(context,args)
    }else{
    	timeout = setTimeout(function(){
      	fun.apply(context,args)
      },time)
    }
  }
  
}

const newDebounce = debounce('要限制的函数',延迟时间,是否立即执行);
newDebounce()

(六) 防抖函数里面的疑问点

  • 这句话的作用是什么: if ( timeout ) clearTimeout ( timeout ) (代码第13行)

    疑问解答: 每次执行定时器的时候,都会返回该定时器对应的 id 整数类型的标识,多次调用时就会生成多个定时器,为了防止定时器之间的影响,就可以通过 clearTimeout 方法通过传入 对应 的 id 来清除对应的定时器

  • 为什么定义这个变量: var callNow = !timeout (代码第15行)

疑问解答: 为了给fun函数定义一个执行条件,既然 immediate 为true 立即执行了,那么fun的执行条件就必须为真,恰巧 timeout 第一次执行的时候是 undefined 去反就为 true

  • 为什么在 setTimeout 里面要给 timeout 重新复制为 null: timeout = null (代码第17行)

    疑问解答: 因为setTimeout 里面的回调函数是异步任务,会在最后执行,所以最后要给 timeout 重新赋值为null ,为了下次防抖函数能正常调用

  • 防抖函数里面的参数 immediate 的作用有无该参数的区别: (代码第8行)

    疑问解答: 当 immediate 为true时会立即执行 fun函数 当immediate 为false或者不传参数的时候,他会依据设定的 延迟时间 time 为基准,等延迟时间结束之后才会执行fun函数

节流

(一) 什么是节流

节流是指连续触发事件执行函数,不会一起执行,而是在单位时间内只执行一次

(二) 节流的作用

节流可以在触发函数行为的频率较高的时候加以限制,只让函数行为触发一次,从而优化函数被多次调用导致的一系列性能和用户体验的问题

(三) 如何实现

封装一个节流的处理函数,节流也是返回的是一个新的函数。

(四) 应用场景

鼠标的移动事件,导致频率非常高,用节流的方式之后单位时间内只触发一次

windown触发resize的时候,不断调整窗口的大小进行触发,用节流只会触发一次

(五) 代码实现

/**
  @desc 节流函数
  @param fun 函数
  @param time 延迟时间 
  @param type 类型 1是使用时间戳限制 2是使用定时器进行限制
*/

const throttle = (fun,time,type=2) => { // 可以通过type判断使用哪一种节流方式,可以默认是定时器版本
		if(type === 1){
    	 nowTime = 0 // 默认第一次触发为0
    }else{
    	 timeout = null 
    }
    
    return function(){  
    
    	let context = this;
      let args = arguments; // 获取this和参数
      if(type === 1){  // 依据类型判断执行那种节流方式
      	let now = Date.now() //获取当前时间戳
        if(now - nowTime > time){  //判断触发的频率
        	fun.apply(context,args)
          nowTime = now  // 重新赋值以便下次调用
        }
      
      } else {
      	if(!timeout){
        	timeout = setTimeout(()=>{
          	timeout = null;
            fun.apply(context,args)
          },time)
        }
      }
    }
}

const newThrottle = throttle(‘要限制处理的函数方法’,延迟时间,节流的方式);
newThrottle();

(六) 节流函数里面的疑问点

  • 节流函数立面的 type为1 和 type 为 2时候 区别在哪: (代码第8行)

    疑问解答: 当 type 为1 的时候 是使用以时间戳为判断条件从而执行fun 函数, type为1 会立即执行 fun函数 当 type 为2 的时候 是使用定时器执行fun 函数,type 为2的时候,会等到 time延迟时间结束之后再执行

防抖和节流的区别

  1. 节流:当type 为 1 的时候,只有当前时间大于上一次的执行时间才执行,当type 为2 时,以有无定时器返回的 id 标识和 定时器的延迟时间为条件判断是否执行的
  2. 防抖:当immediate 为true 时候 会立即执行,以有无生成定时器返回的id为判断条件,成立则执行,当immediate为false时候,以定时器的延迟时间为条件执行的
  3. 防抖是通过setTimeout 在一定时间间隔内将多次触发合并成一次触发,节流则是,单位时间内控制触发的频率,单位时间内只执行一次