防抖函数&节流函数

节流函数和防抖函数是 JS 比较重要的概念,应用好了可以提高很大的性能,在面试中也是很高频的一个考点。下面一起来看看这两种方法是如何使用的:

防抖函数(debounce):

概念:

在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时

生活中的栗子:

如果有人进电梯(触发事件),那电梯将在 10 秒钟后出发(执行事件),这时如果又有人进电梯了(在 10 秒内再次触发该事件),我们又得等 10 秒再出发(重新计时)。

代码栗子:

// 防抖函数
function debounce(fn, wait) {
  let timer = null;
  return function() {
    if (timer) {
      // 如果有一个函数在等待执行 清除定时器 下面重新计时
      clearTimeout(timer);
      timer = null;
    }
    timer = setTimeout(function() {
      fn(); // wait时间后(期间不能再触发debounce) 执行回调
    }, wait);
  };
}
let actionFn = function() {
  console.log('回调'); // 要执行的函数
};
setInterval(debounce(actionFn, 500), 1000); // 第一次在1500ms后触发,之后每1000ms触发一次
setInterval(debounce(actionFn, 2000), 1000); // 还没执行就一直重复触发,不会执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

可以这样理解

函数触发停止一段时间后(期间不能再触发 debounce,否则将重新计时),再执行回调函数

机制:

防抖函数主要利用定时器的延迟执行特性,根据是否有定时器在等待执行:

  • 触发了一个事件后:如果有一个定时任务待执行,就清除定时器,重新计时。
  • 如果没有任务待执行,就定时执行这个事件。

应用场景:

  1. 表单的连续点击,防止重复提交。比如重复发送一篇文章。
  2. 类百度的搜索,连续输入等输入停止后再搜索。
  3. 一直拖动浏览器窗口,只想触发一次事件等。

节流函数(throttle):

概念:

规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行(单位时间内有事件被多次触发则,只生效一次)

生活中的栗子:

漏水的自来水水龙头,尽管水龙头里面有很多水(一直在触发事件),但还是一滴一滴的往下滴(单位事件内只生效一次)。

代码栗子:

// 节流函数 每隔一定时间就执行
function throttle(fn, gapTime) {
  let _lastTime = null;
  return function() {
    let _nowTime = +new Date();
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      // !_lastTime 第一次进入
      fn(); // 当前时间- 上次执行的时间 超过 给定时间间隔 就执行回调
      _lastTime = _nowTime; // 触发后,上次执行时间赋值为当前时间
    }
  };
}
let actionFn = () => {
  console.log('回调'); // 要执行的函数
};
setInterval(throttle(actionFn, 1000), 10);
// 每隔10毫秒都会触发一次throttle,每隔一秒触发一次actionFn回调(1秒内再次触发被丢弃)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • 一开始_lastTime 没有值,触发回调,保存当前触发的时间为_lastTime
  • 10 毫秒触发一次,每次触发 用_nowTime-_lastTime 超过给定的时间(1 秒),就再次触发回调

机制:

节流函数根据时间差是否超过给定时间(gapTime)来决定是否触发回调。

应用场景:

  1. 自动保存草稿功能,当用户在输入的时候(一直触发事件),单位时间内只保存一次草稿。
  2. 游戏中的刷新率

怎么给回调函数传参?

通过 ES6 的...扩展符来保存回调函数的参数,并传给回调函数

function throttle(fn, gapTime, ...arr) {
  let _lastTime = null;
  return function() {
    let _nowTime = +new Date();
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      // !_lastTime 一开始的时候没有值为true
      fn(arr);
      _lastTime = _nowTime;
    }
  };
}
let actionFn = arr => {
  console.log('执行函数', arr); // arr是个数组 接收不定数量的参数 没有参数是个空数组
};
setInterval(throttle(actionFn, 1000, '执行函数参数1', '执行函数参数2'), 10); // 节流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

应用实例,需要加个括号:

function throttle(fn, gapTime, ...arr) {
  let _lastTime = null;
  return function() {
    let _nowTime = +new Date();
    if (_nowTime - _lastTime > gapTime || !_lastTime) {
      // !_lastTime 一开始的时候没有值为true
      fn(arr);
      _lastTime = _nowTime;
    }
  };
}
let actionFn = arr => {
  console.log('执行函数', arr); // arr是个数组 接收不定数量的参数 没有参数是个空数组
};
document.onclick = () => {
  throttle(actionFn, 1000, '执行函数参数1', '执行函数参数2')(); // 执行闭包函数
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

作用和本质:

  • 防抖函数和节流函数主要解决的问题是:防止函数”短时间“的重复执行

  • 它们本质上是:在时间轴上控制函数的执行次数

Last Updated: 11/4/2018, 3:47:41 PM