🌟手写节流throttle与防抖debounce - 图1

节流

函数执行一次后,只有在大于设置的执行周期后才会执行第二次。持续触发事件时,保证一定时间段内只调用一次事件处理函数

  • 规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效
  • 好比玩游戏时法师释放的技能,它有冷却时间,在一定时间内,只能释放一次技能

原理

原理是通过判断是否到达规定时间来触发函数。

运用场景

  • 鼠标不断点击触发,mousedown 事件的执行(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用节流来判断

代码实现

用一个可拖拽的div模拟:

🌟手写节流throttle与防抖debounce - 图2

🌟手写节流throttle与防抖debounce - 图3
结果:

🌟手写节流throttle与防抖debounce - 图4

导致移动一点点都会触发事件,打印了好多😭,设想如果里面设计dom查询之类的,那么性能定会堪忧,so,节流来帮忙!

  1. const div1 = document.getElementById('div1')
  2. let timer = null
  3. div1.addEventListener('drag', function (e) {
  4. if (timer) {
  5. return
  6. }
  7. timer = setTimeout(() => {
  8. console.log(e.offsetX, e.offsetY)
  9. timer = null
  10. }, 100)
  11. })

结果为每隔100毫秒打印一次😄,为了方便封装一哈:

  1. const div1 = document.getElementById('div1')
  2. function throttle(fn, delay = 100) {
  3. let timer = null
  4. return function () {
  5. if (timer) {
  6. return
  7. }
  8. timer = setTimeout(() => {
  9. fn.apply(this, arguments)
  10. timer = null
  11. }, delay)
  12. }
  13. }
  14. div1.addEventListener('drag', throttle(function (e) {
  15. console.log(e.offsetX, e.offsetY)
  16. }))

防抖

维护一个计时器,在规定的delay时间后触发函数,在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

  • 当持续触发事件时,一定时间段内没有再次触发事件,事件处理函数才会执行一次,如果在设定的时间到来之前,又一次触发了事件,就重新开始延时
  • 好比玩游戏时英雄回泉水,当点击了回泉水时,就不能中断,如果中断就得重新来过

原理

其原理是维护一个计时器,规定在 delay 时间后触发函数,但是在 delay 时间内再次触发的话,就会取消之前的计时器而重新设置;这样一来,只有最后一次操作能被触发。

运用场景

  • input 输入框实现模糊匹配功能,用户在不断输入值时,用防抖来节约请求资源
  • window 触发 resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

代码实现

input 输入框未做处理时

🌟手写节流throttle与防抖debounce - 图5

🌟手写节流throttle与防抖debounce - 图6
结果:

🌟手写节流throttle与防抖debounce - 图7

显而易见,每次输入都会触发,这很不理想,那么用防抖优化一哈,让它等个500毫秒:

  1. const input1 = document.getElementById('input1')
  2. let timer = null
  3. input1.addEventListener('keyup', function () {
  4. if (timer) {
  5. clearTimeout(timer)
  6. }
  7. timer = setTimeout(() => {
  8. // 模拟触发 change 事件
  9. console.log(input1.value)
  10. // 清空定时器
  11. timer = null
  12. }, 500)
  13. })

结果:

🌟手写节流throttle与防抖debounce - 图8

为了方便起见,我们简单封装一下:

  1. // 防抖
  2. function debounce(fn, delay = 500) {
  3. // timer 是闭包中的,避免外部修改
  4. let timer = null
  5. return function () {
  6. if (timer) {
  7. clearTimeout(timer)
  8. }
  9. timer = setTimeout(() => {
  10. fn.apply(this, arguments)
  11. timer = null
  12. }, delay)
  13. }
  14. }
  15. input1.addEventListener('keyup', debounce(function (e) {
  16. console.log(e.target)
  17. console.log(input1.value)
  18. }, 600))

结果:

🌟手写节流throttle与防抖debounce - 图9

欢迎打家纠错😂
参考文章