深耕系列之防抖和节流函数

498 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

术语理解

防抖(debounce):防止抖动引起问题,核心在于抖动,间隔。一段时间内连续被触发,则只在最后一次执行。

节流(throttle):节约流量,提高性能,核心在于减少。侧重于一段时间内只执行一次。

可发现,防抖和节流都是针对高频率触发事件的优化,那么都应用在哪些场景下呢?

应用场景

防抖

  1. 用户在input框输入用户名内容时,校验用户名是否有效,可节省请求资源。
  2. 用户点击button时,避免用户多次点击,当然这里也可以采用第一次点击置灰的方案。
  3. window触发resize事件,不断调整窗口大小而导致多次调用resize事件。

节流

  1. 监听滚动事件,滑到底部自动加载更多。
  2. 计算鼠标移动距离。
  3. Dom元素的拖拽功能。

可发现,函数节流和防抖出现的场景一般都和DOM的事件监听有关,那么是怎么实现的?

手写代码

防抖

思路:防抖函数针对的是间隔,所以考虑使用setTimeout来模拟间隔时间,如果频繁触发,则刷新间隔时间。

/**
 * @param {Function} func
 * @param {number} wait
 * @return {*}
 */
function debounce(fn, wait) {
	// 闭包写法
  let timeout = null

  return function() {
		// 如果在间隔时间内访问,就清除定时器
		if (timeout) {
			clearTimeout(timeout)
		}
		
		timeout = setTimeout(() => {
			// 使用箭头函数和apply来绑定this指向,避免指向问题
			fn.apply(this, arguments)
			timeout = null
		}, wait)
  }
}

// 使用
function log(value) {
	console.log(value)
}
debounce(log, 500)('参数')

节流

思路:节流函数针对是一段时间内只执行一次,所以考虑用setTimeout来设置间隔时间,如果频繁调用,setTimeout不为null的话就不执行。

/**
 * @param {Function} func
 * @param {number} wait
 * @return {*}
 */
function throttle(fn, wait) {
	// 闭包写法
  let timeout = null

  return function() {
		// 如果在间隔时间内访问,不处理
		if (timeout) {
			return
		}
		
		timeout = setTimeout(() => {
			// 使用箭头函数和apply来绑定this指向,避免指向问题
			fn.apply(this, arguments)
			timeout = null
		}, wait)
  }
}

// 使用
function log(value) {
	console.log(value)
}
throttle(log, 500)('参数')

总结

防抖和节流都可以通过setTimeout来实现,目的都是节省计算资源,但需要注意的是,setTimeout是宏任务,如果js执行比较久,会影响到setTimeout的定时准确度。