节流与防抖

防抖(debounce)和节流(throttle)

debounce英 [di'bauns] throttle英 [ˈθrɒtl]

本质上是优化高频率执行代码的一种手段

如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能

为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用 防抖(debounce)节流(throttle) 的方式来减少调用频率

定义
  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效

  • 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

防抖

为什么会出现debounce和throttle

防抖和截流是针对响应跟不上触发频率这类问题的两种解决方案。

在给DOM绑定事件时,有些事件我们时无法控制触发频率的。如鼠标移动事件onmousemove,滚动滚动条事件onscroll,窗口大小改变事件onresize,瞬间的操作都会导致这些事件会被高频触发。如果事件的回调函数较为复杂,就会导致响应跟不上触发,出现页面卡顿,假死现象。在实时检查输入时,如果我们绑定onkeyup事件发请求去服务器端检查,用户输入过程中,事件的触发频率也会很高,会导致大量的请求发出,响应速度会大大跟不上触发

总结:以下场景往往由于事件频繁被触发,而重复执行DOM操作,资源加载等重行为、会导致UI停顿甚至浏览器崩溃。

  1. window对象的resize、scroll和拖拽时的mousemove事件

  1. 射击游戏中的mousedown,keydown事件

  1. 类似百度搜索提示keyup事件

问题分析

DOM操作比非DOM交互需要更多的内存和CPU事件,连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时候甚至会崩溃

实际上对于window的resize事件,实际需求大多为停止改变大小n毫秒后执行后续操作、而拖拽的mousemove事件函数则是以一定的频率执行后续处理。比如拖拽事件、可以在用户能够接受的范围内更改代码的执行频率、mousemove的触发频率大概为10ms【100次】一次,而当我们设置执行事件为50ms【20次】一次时,用户也不会察觉、这样我们就可以在不影响用户体验的前提下,提高性能。

针对这两种需求就出现了防抖(debounce)和节流(throttle)两种解决方法

debounce防抖

debounce,去抖动。策略是当事件被触发时,设定一个周期延迟动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。这是debounce的基本思想,在后期又扩展了前缘debounce,即执行动作在前,然后设定周期,周期内有事件被触发,不执行动作,且周期重新设定

debounce的特点是当事件快速联系不断触发时,动作只会执行一次。延迟debounce,是在周期结束时执行。但当触发有间断,且简短大雨我们设定的时间间隔时,动作就会有多次执行

总结:什么是debounce,高频率触发的事件,我们最终只让他执行一次

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
          margin: 0;
          padding: 0;
        }
        #common {
          position: absolute;
          left: 0;
          top: 0;
          border: 1px solid #000;
          width: 300px;
          height: 600px;
        }
        #special {
          position: absolute;
          left:400px;
          top: 0;
          border: 1px solid #000;
          width: 300px;
          height: 600px;
        }
      </style>
</head>
<body>
    节流代码
<div id="common">
  throttle
</div>
<div id="special">
  debounce
</div>
<script>
  var delay = 300;
  var common = document.getElementById('common')   // 获取页面的左边
  var special = document.getElementById('special')   // 获取页面的右边


  function addlist() { // 监听事件的响应事件,执行dom操作。
    special.innerHTML += '<li>k</li>'
  }

  function commonWay() { // 这是执行了普通的函数
    common.innerHTML += '<li>k</li>'
  }

  // tottle的实现,也就是节流的实现,就是设置了一个一开始函数运行的时间戳进行执行
  var startTime, timestamp, timer;

  function throttle(fn, delay) {
    // timestamp = +new Date()
    timestamp = new Date().getTime(); // 时间戳 timestamp = 10:23:10  10:23:20 10:23:59 10:23:60 
    clearTimeout(timer)
    if (!startTime) {
      startTime = timestamp // startTime = 10:23:59
    }
    if (timestamp - startTime >= delay) {
      fn() // 这里才会调用
      startTime = timestamp
    } else {
      timer = setTimeout(function () {
        fn()
      }, delay)
    }
  }
    // 防抖
  function debounce(fn, delay) {     // 定义一个debounce函数
    clearTimeout(fn.timeid)
    fn.timeid = setTimeout(function () {
      fn()
    }, delay)
  }
//   调整窗口大小触发
  window.addEventListener('resize', function () {
    throttle(commonWay, 200); // 节流 100ms执行一次,1s执行了10次; 
    debounce(addlist, delay); // 防抖
  })
</script>
</body>
</html>

面试题:

什么是防抖:在频繁触发某一个事件时,一段时间内不再触发该事件后才会去调用对应的回调函数,在设定间隔时间内如果下一次事件被触发, 那么就重新开始定时器,直到事件触发结束。

什么时候使用:防抖用于高频触发的事件

特点:高频触发事件处理程序,只执行他的最后一次

总结

以下场景往往由于事件频繁被触发,而重复执行DOM操作、资源加载等重行为、会导致UI停顿甚至浏览器崩溃。

1、window对象的resize、scroll和拖拽时的mousemove事件

2、射击游戏中的mousedown、keydown事件

3、类似百度搜索提示keyup事件

防抖: 在事件多次触发时,通过防抖,只执行最后一次事件处理程序

节流: 降低事件处理程序执行的频率。 比如,onmousemove事件如果一秒钟执行200次,通过节流可以只执行20次

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值