原理

规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。

实现

时间戳实现

注意:第一次事件会被触发,最后一次不会触发函数

  1. function throttle(func, wait) {
  2. let _this, args;
  3. // 之前的时间戳
  4. let old = 0;
  5. return function () {
  6. // 保存this
  7. _this = this;
  8. //保存arguments
  9. args = arguments;
  10. // 获取当前时间戳
  11. let now = new Date().valueOf();
  12. if (now - old > wait) {
  13. // 立即执行
  14. func.apply(_this, args);
  15. lod = now;
  16. }
  17. }
  18. }

注意和防抖函数进行区分

定时器实现

第一次不会被触发,最后一次会触发

  1. function throttle(func, wait) {
  2. let _this, args, timeout;
  3. return function () {
  4. _this = this;
  5. args = arguments;
  6. if (!timeout) {
  7. timeout = setTimeout(() => {
  8. timeout = null;
  9. func.apply(_this, args);
  10. }, wait)
  11. }
  12. }
  13. }

节流进阶

原生的节流函数有第三个参数,用于控制是否首次事件是否被立即调用,以及最后一次事件是否被调用

  1. container.onmousemove = _.throttle(doThrottle, 1000, {
  2. leading: false, //是否立即执行
  3. trailing: true //最后一次是否执行
  4. //两者不能同为false,否则就会产生bug,会导致触发事件立即执行一次后就失效了!
  5. })

实现

  1. function throttle(func, wait, options) {
  2. let _this, args, timeout;
  3. let old = 0; //时间戳
  4. //如果没有options就将其设置为空对象
  5. if (!options) options = {};
  6. let later = function () {
  7. old = new Date().valueOf();
  8. timeout = null;
  9. func.apply(_this, args);
  10. }
  11. return function () {
  12. _this = this;
  13. args = arguments;
  14. let now = new Date().valueOf();
  15. if (options.leading === false && !old) {
  16. old = now;
  17. }
  18. if (now - old > wait) {
  19. // 第一次直接执行
  20. if (timeout) {
  21. clearTimeout(timeout);
  22. timeout = null;
  23. }
  24. func.apply(_this, args);
  25. old = now;
  26. } else if (!timeout && options.trailing !== false) {
  27. //最后一次也被执行
  28. timeout = setTimeout(later, wait)
  29. }
  30. }
  31. }

测试:

  1. function doThrottle(e) {
  2. container.innerHTML = count++
  3. }
  4. container.onmousemove = throttle(doThrottle, 1000,{
  5. leading:false,
  6. trailing:true
  7. });

应用场景

  1. DOM元素的拖拽功能的实现
  2. 射击游戏中的每隔一段时间射击
  3. 计算鼠标移动的距离
  4. 监听scroll滚动事件
  5. 搜索联想
  6. 高频点击提交,表单重复提交

防抖节流之间的异同比较

  1. 相同:
    • 都可以通过setTimeout实现
    • 目的都是:降低回调执行频率,节省计算资源
  2. 不同:
    • 函数防抖: 在一段连续操作结束后,处理回调,利用clearTimeout和setTimeout实现.
    • 函数节流:在一段连续操作中,每一段时间只执行一次,频率较高的时间中使用来提高性能.
    • 函数防抖关注一定时间连续触发的事件只在最后执行,而函数节流侧重于一段时间内只执行一次!