知识扩展之防抖节流

324 阅读2分钟

防抖 & 节流

理解: 虽然二者都有延迟当前动作的反馈,但是防抖的延迟时间是确定的,延迟周期内如果有新动作进入,旧的动作将会被取消。 // 而节流是提前设置了一个阀门,只有当阀门打开的时候,该动作才有机会执行。如果阀门是关闭的,那这个动作就不会进入执行区。 // 个人理解防抖是后置的处理高频事件方式,而节流是前置处理。防抖机制隐含了一个优先级的概念,后到的先执行,因此事件的进入事件越晚优先级实则越高, // 而优先级最高的具备执行权,而进入时间这个准入条件是不由开发者提前预设的,事件的执行更加离散无规则。而缓冲机制并没有为事件分配权重, // 只是设置了一个均匀频率的信号量,该信号量的开启和关闭是决定能否进入执行区的条件,而与事件无关,准入条件是人为设置的,相对来说执行更规律。

防抖: 动作绑定事件,动作发生后一定时间后触发事件,在这段时间内,如果该动作又发生,则重新等待一定时间再触发事件

事件句柄的频繁触发,造成页面频繁渲染,造成视觉上的抖动(Ep: 频繁的点击事件) 解决方案: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时.

function debounce(fn, delay = 200) {
	let timer;
	// 函数需要有单独的作用域 及其参数
	return function () {
		let context = this;
		let args = arguments;
		if (timer) clearTimeout(timer); // 清空定时器
		timer = setTimeout(() => {
			fn.apply(context, args)
		}, delay)
	}
}
  1. 使用debounce函数进行封装 返回一个可执行的函数, 保证可执行函数的作用域和参数干净
  2. 每次进入debounce,先清空之前的触发事件,保证事件触发的唯一性
  3. 使用apply改变this指向, 使用arguments来扩展参数

节流: 动作绑定事件,动作发生后一段时间后触发事件,在这段时间内,如果动作又发生,则无视该动作,直到事件执行完后,才能重新触发

规定在一个单位时间内,只能触发一次函数.如果这个单位时间内触发多次函数,只有一次生效.

  • 时间戳方案 -
  function throttle(fn, delay = 500) {
  	let last, timer;
  	return function (...args) {
  		const time = Date.now()
  		if ((last && time > last + delay) || !last) {
  			last = Date.now()
  			fn.apply(this, args)
  		}
  	}
  }
  • 定时器执行 - 制作一个延时任务队列,逐一执行
function throttle(fn, delay = 200) {
  let timer
  return function (...args) {、
    if (!timer) {
       timer = setInterval(() => {
         fn.apply(this, args)
         timer = null
         clearInterval(timer)
      }, delay)
    }
  }
}