深入理解JavaScript——防抖与节流

简介: 防抖和节流都是闭包的应用,先理解闭包,再理解防抖和节流

防抖(debounce)


先不说概念,按自己的理解,在单反里,有防抖机制。因为人在拿着单反的时候会手抖(单反重),按下快门的瞬间,照片会糊,所以有防抖机制,以防止新手把照片拍糊

单反中的防抖是防止抖动,让人拍出清晰的照片,JavaScript 中的防抖是为了什么?

同理,它的作用也是防止抖动。试想当你频繁触发一个事件时,就会引起不必要的性能损失,那么让该事件在停止触发后再触发,以此减少部分性能


防抖的定义

防抖就是要延迟执行,你一直操作触发事件一直不执行,当你停止操作等待多少秒后才执行


也就是说不管事件触发频率有多高,一定在事件触发 n 秒后执行。如果在事件触发的 n 秒又触发了这个事件,那就以新事件的事件为准,n 秒后才执行。总之,要等你触发完事件 n 秒内不再触发事件,它才执行


手写防抖

根据定义,我们知道要在时间 n 秒后执行,那么我们就用定时器来实现

function debounce(event, wait) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer); // 清除setTimeout,使其回调函数不执行
    timer = setTimeout(() => {
      event.apply(this, args);
    }, wait);
  };
}


代码很简单,即当还在触发事件时,就清除 timer,使其在 n 秒后执行,但此写法首次不会立即执行,为其健壮性,需加上判断是否第一次执行的第三个参数 flag,判断其是否立即执行


function debounce(event, wait, flag) {
  let timer = null;
  return function (...args) {
    clearTimeout(timer);
    if (!timer && flag) {
      event.apply(this, args);
    } else {
      timer = setTimeout(() => {
        event.apply(this, args);
      }, wait);
    }
  };
}


防抖场景

窗口大小变化,调整样式

window.addEventListener('resize', debounce(handleResize, 200));


搜索框,输入后 1000 毫秒搜索

debounce(fetchSelectData, 300);


表单验证,输入 1000 毫秒后验证

debounce(validator, 1000);


防抖帝王库

两大工具库都有防抖源码,可供参考

lodash-debounce

underscore-debounce


节流(throttle)


顾名思义,一节一节的流,就好似控制水阀,在事件不断触发的过程中,固定时间内执行一次事件


手写节流

因为是固定时间内执行一次时间,所以我们有两种实现方法,一用时间戳,二用定时器


时间戳

function throttle(event, wait) {
  let pre = 0;
  return function (...args) {
    if (new Date() - pre > wait) {
      // 当 n 秒内不重复执行
      pre = new Date();
      event.apply(this, args);
    }
  };
}

使用时间戳虽然能实现节流,但是最后一次事件不会执行


定时器

function throttle(event, wait) {
  let timer = null;
  return function (...args) {
    if (!timer) {
      timer = setTimeout(() => {
        timer = null;
        event.apply(this, args);
      }, wait);
    }
  };
}

使用定时器实现节流,虽然最后一次能触发,但是第一次不会触发


时间戳 + 定时器

为解决第一次和最后一次都可以触发,把两者结合起来

function throttle(event, wait) {
  let pre = 0,
    timer = null;
  return function (...args) {
    if (new Date() - pre > wait) {
      clearTimeout(timer);
      timer = null;
      pre = new Date();
      event.apply(this, args);
    } else {
      timer = setTimeout(() => {
        event.apply(this, args);
      }, wait);
    }
  };
}


节流场景

scroll 滚动

window.addEventListener('scroll', throttle(handleScroll, 200));


input 动态搜索

throttle(fetchInput, 300);


节流帝王库

lodash-throttle

underscore-throttle


总结


防抖:只执行最后一次。事件持续触发,但只有等事件停止触发后 n 秒后才执行函数

节流:控制执行频率。持续触发,每 n 秒执行一次函数

对比图:

image.png

线上 demo(司徒正美的 demo):防抖节流


参考资料


  • awesome-coding-js
  • 防抖节流场景及应用
  • 函数防抖与函数节流
相关文章
|
3月前
|
前端开发 JavaScript UED
JavaScript防抖和节流的使用及区别
JavaScript防抖和节流的使用及区别
105 57
|
6月前
|
前端开发 JavaScript Java
【JavaScript】JavaScript 防抖与节流:以游戏智慧解锁实战奥秘
【JavaScript】JavaScript 防抖与节流:以游戏智慧解锁实战奥秘
66 3
|
6月前
|
JavaScript 前端开发 UED
深入理解JavaScript中的节流与防抖技术
理解并合理运用节流与防抖技术,可以帮助我们优化事件处理函数的执行频率,从而提升应用的性能和用户体验。这两种技术通过减少不必要的计算和DOM操作,使得Web应用程序能够更加流畅地运行。 通过掌握防抖和节流的实现原理及应用场景,开发者可以更加灵活地编写高效且性能优化的代码,对于面对高频事件处理时尤其重要。在开发中合理选择使用防抖或节流,将直接影响到应用的响应性和效率。
58 1
|
2月前
|
前端开发 JavaScript UED
JavaScript 中的函数防抖与节流详解及实用场景
在前端开发中,处理用户频繁触发的事件,如输入框的输入、按钮点击、窗口调整大小等,常常需要优化性能以减少无效操作。为此,函数防抖(debounce)和函数节流(throttle)是两种常见的性能优化手段。本文将详细介绍两者的区别与实现,并探讨它们的应用场景。
42 1
|
3月前
|
JavaScript 前端开发
js防抖函数返回值问题解决方案
本文介绍了如何在JavaScript中创建一个带有返回值的防抖函数,通过结合Promise来实现。这种防抖函数可以在事件触发一定时间后再执行函数,并能处理异步操作的返回值。文章提供了防抖函数的实现代码和如何在实际项目中使用该防抖函数的示例。
35 1
|
4月前
|
JavaScript 前端开发 UED
JS 防抖与节流
防抖和节流是优化高频事件处理的技术。针对如`scroll`、`resize`等频繁触发的事件,它们能有效减少不必要的回调执行,节省资源。防抖确保在一段时间内仅执行最后一次操作,适用于输入框自动补全等场景;而节流则按固定间隔执行函数,适合拖拽、滚动事件。通过简单的JavaScript实现,可以显著提升应用性能和用户体验。
37 1
JS 防抖与节流
|
7月前
|
JavaScript 前端开发 UED
js的防抖节流
js的防抖节流
40 1
|
7月前
|
JavaScript 前端开发 UED
js的节流
js的节流
37 0
|
7月前
|
测试技术
js_防抖与节流(闭包的使用)
js_防抖与节流(闭包的使用)
48 0
|
7月前
|
JavaScript
JS中防抖和节流的区别是什么
JS中防抖和节流的区别是什么
49 0