防抖与节流

172 阅读2分钟

前言


在前端开发过程中,经常会遇到一些触发频率极高的按钮、操作、交互事件等等。如果我们不对这些事件做处理, 不但对于浏览器的压力,以及对后端接口的压力十分大,非常容易出现浏览器崩溃,接口卡死等等情况,这个时候我们就需要 借用防抖与节流优化对应的事件

节流与防抖的本质


这两个东西都以闭包的形式存在

通过对事件的回调函数进行缓存,使用定时器进行控制事件的触发频率。

例子


先说一个在后台管理系统常见的例子,很多后台管理系统会出现AutoComplete自动完成输入框为用户提供输入建议,这种输入框会监听change事件, 如果不做限制的话,我们输入十个字符就会调用接口十次

1.gif

在运行的时候会发现存在一个问题,这个接口调用频率太高了,同理的还有监听scrollTop,抢购按钮等

debounce 防抖


防抖:在设定的时间内频繁触发函数时,以最后一个函数为准。

防抖其实就是记录这次执行函数,放入定时器中,如果在设定时间内再次出现就清除定时器,重新设置定时器。

简单实现:

function debounce (fn, delay = 1000) {
	// 设置定时器
	let timer = null
	return function () {
		const context = this
		const args = arguments
		if (timer) {
			// 有定时器就清除
			clearTimeout(timer)
		}
		// 重新记录函数
		timer = setTimeout(function () {
			fn.apply(context, args)
		}, delay)
	}
}

Throttle 节流


节流:在设定的时间内,记录第一个函数,并在时间结束后执行此函数。

在抢购按钮、scrollTop监听等事件中会用到,并会使这些函数以设定的时间频率触发。

简单实现:

function throttle (fn, delay = 1000) {
	// 记录最后函数触发时间
	let last = 0
	return function () {
	  const context = this
	  const args = arguments
	  const now = +new Date()
		// 当前时间与本次函数触发时间差是否大于时间阙值
	  if (now - last >= delay) {
	    last = now
	    fn.apply(context, args)
	  } 
	}
}
	

优化 debounce throttle

debounce 优化虽然好,但是缺点在于如果你一直在设定时间内触发此函数会导致函数一直不执行,会使用户产生疑惑, throttle 的缺点在于,如果用户正好在时间阙值内点击按钮,不会触发此次函数,并且时间阙值到了也不会执行。 所以我们可以使用 throttle 优化 debounce,在一定周期内,多次点击会缓存函数,在时间阙值结束后执行。

function throttle (fn, delay = 100) {
  let last = 0
  let timer = null
  return function () {
    const context = this
    const args = arguments
    const now = +new Date()
    if (now - last < delay) {
      clearTimeout(timer)
      timer = setTimeout(function () {
        last = now
        fn.apply(context, args)
      }, delay)
    } else {
      last = now
      fn.apply(context, args)
    }
  }
}