在前端开发过程中经常会遇到一些特殊功能需要不断调用某种事件或方法,如:
1、监听窗口大小resize
2、懒加载监听滚动信息scroll
3、拖拽事件的mousemove
4、监听输入框input事件
…..
一般情况下,我们也不需要每次变化都去进行处理,次次都处理的话会很浪费资源,用户设备配置低的情况下还有可能出现卡死。我们可以限定触发次数,对于此类场景出现了两种解决方案debounce(防抖)和throttle(节流)。

防抖(debounce)

例子、当前瀑布流页面,监听scroll事件,监听当前滚动条位置判断是否已到达底部需要加载新数据,scoll是滚动条一动则触发。
以上例子我们都可以防抖函数解决,定义好延迟时间,每次重新触发事件则更新延迟,等用户停止操作后才执行方法。

  1. /**
  2. * 防抖
  3. * @param {Function} func
  4. * @param {Number} delay
  5. */
  6. function debounce(func, delay = 100){
  7. let timer, context, args;
  8. return function(){
  9. context = this, args = arguments;
  10. if(timer) clearTimeout(timer);
  11. timer = setTimeout(function(){
  12. func.apply(context, args);
  13. }, delay);
  14. }
  15. }

节流(throttle)

例子、搜索框输入值使用input监听,每输入一个文字则发生一次模糊搜索。
如果一个函数高频触发,那么就可以定义它在一定的时间间隔后触发,减少执行次数。

  1. // 时间戳版本
  2. /**
  3. *
  4. * @param {Function} func
  5. * @param {Number} delay
  6. */
  7. function throttle(func, delay = 500){
  8. let previous = 0, // 记录上次触发的时间戳
  9. now, // 记录当前时间戳
  10. context, args;
  11. return function(){
  12. now = Date.now(),
  13. context = this,
  14. args = arguments;
  15. // 判断当前时间距离上次触发时间是否在间隔后
  16. if(now - previous > delay){
  17. func.apply(context, args);
  18. previous = now;
  19. }
  20. }
  21. }
  22. // 定时器版本
  23. function throttle(func, delay = 500){
  24. let timer, // 保存定时器id
  25. context, args;
  26. return function(){
  27. // 当定时器存在则终止此次操作
  28. if(timer) return;
  29. context = this, args = arguments;
  30. timer = setTimeout(function(){
  31. func.apply(context, args);
  32. // 清除定时器记录
  33. timer = null;
  34. }, delay);
  35. }
  36. }

防抖和节流区别

防抖是定义程序在触发事件操作停止后才执行程序,每次触发事件都更新执行程序的时间。节流是定义程序在指定时间间隔内只执行一次。

调用方式

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. <style>
  9. *{margin: 0; padding: 0;}
  10. #scroll{width: 100%;}
  11. .item{margin-bottom: 50px; width: 100%; height: 100px; background: blue;}
  12. </style>
  13. </head>
  14. <body>
  15. <button id="send">send</button>
  16. <div id="scroll">
  17. <div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div>
  18. </div>
  19. <script src="./debounce.js"></script>
  20. <script src="./throttle.js"></script>
  21. <script>
  22. window.addEventListener("scroll", debounce(function(e){
  23. // 当停止事件操作500毫秒后执行
  24. console.log(e)
  25. }, 500));
  26. send.addEventListener("click", throttle(function(e){
  27. // 每500毫秒间隔触发一次
  28. console.log(e)
  29. }, 500))
  30. </script>
  31. </body>
  32. </html>

总结

throttle和debounce都是通过减少实际逻辑处理的执行次数来提高程序的性能。比如说,我在输入框输入触发input向后台请求模糊查询,实际上input事件该触发多少次还是多少次,但我的请求次数变少了,ajax减少了,从而提高性能。