防抖(debounce)和节流(throttle)的理解

700 阅读3分钟

开发中时常有人会谈到防抖和节流的使用,这里我就说一下我对于这个两者的理解

首先: 无论是防抖还是节流最终的目的都是避免回调函数中的处理每次都执行

其次就是看使用场景,选择合适的方式进行

一、防抖:

1.1 什么是防抖

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

1.2 应用场景

(1) 用户在输入框中连续输入一串字符后,只会在输入完后去执行最后一次的查询ajax请求,这样可以有效减少请求次数,节约请求资源;

(2) window的resize、scroll事件,不断地调整浏览器的窗口大小、或者滚动时会触发对应事件,防抖让其只触发一次; 高频率触发的事件,在指定的单位时间内,只响应最后一次,如果在指定的时间在触发,则重新计算时间(后面触发的事件执行,替代了前面的事件)

function debounce(fn,time) {
      let timeout = null; // 创建一个标记用来存放定时器的返回值
      return function () {
        clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
        timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
          fn.apply(this, arguments);//arguments是传入的参数
        }, time);
      };
    }
    function debounceFn() {
      console.log('防抖成功');
    }

    let inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(debounceFn,5000)); // 防抖

二、节流:

2.1 什么是节流

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

2.2 应用场景

(1)鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;

(2)在页面的无限加载场景下,需要用户在滚动页面时,每隔一段时间发一次 ajax 请求,而不是在用户停下滚动页面操作时才去请求数据;

(3)监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断; 高频率触发的事件,在指定的单位时间内,只响应第一次(前面触发的执行前,忽略后面的事件)

function throttle(fn,time) {
      let istrue = true; // 通过闭包保存一个标记
      return function () {
        if (!istrue) return; // 在函数开头判断标记是否为true,不为true则return
        istrue = false; // 立即设置为false
        setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
          fn.apply(this, arguments);
          // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
          istrue = true;
        }, time);
      };
    }
    function throttleFn(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(throttleFn,500));

三、防抖和节流的使用场景

防抖(debounce)

1.search搜索联想时,用户正在不断输入,用防抖可以来节约请求资源。

2.window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

节流(throttle)

1.鼠标不断移动触发,mousemove(在上一次事件执行完毕后再开始下一次事件的执行)

2.监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断