Skip to content

防抖(debouncing)节流(throttling)

  • 防抖:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。(最后一次)
  • 节流:在事件被触发n秒后,保证n秒内只执行一次,如果在n秒内被多次触发,只会执行一次。(只一次)

防抖 (debouncing)

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

应用场景

  • 搜索框输入查询
  • 窗口大小resize
  • 按钮提交
js
function debounce(fn, delay) {
  let timer = null;
  return function () {
    const context = this;
    const args = arguments;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, delay);
  };
}

举个简单的例子:在搜索框中输入内容,如果用户在300ms内继续输入,则重新计时,直到用户停止输入300ms后,才会触发搜索事件。

js
const input = document.getElementById('input');
input.addEventListener('input', debounce(function () {
  console.log(this.value);
}, 300));

手写防抖

手写防抖的实现思路:

  1. 使用闭包保存定时器
  2. 返回一个函数,该函数在执行时会清除定时器,并重新设置定时器
  3. 在定时器到期后执行传入的函数
js
<input type="text" id="search" placeholder="Search...">
<div id="result"></div>
<script>
    const searchInput = document.getElementById('search');
    const resultDiv = document.getElementById('result');

    const fetchResults = debounce(function(query) {
        // 模拟 API 请求
        resultDiv.innerText = `Searching for: ${query}`;
    }, 300);

    searchInput.addEventListener('input', (event) => {
        fetchResults(event.target.value);
    });
</script>

loadash防抖

js
import _ from 'lodash';

const searchInput = document.getElementById('search');
const resultDiv = document.getElementById('result');

const fetchResults = _.debounce(function(query) {
    // 模拟 API 请求
    resultDiv.innerText = `Searching for: ${query}`;
}, 300);

searchInput.addEventListener('input', (event) => {
    fetchResults(event.target.value);
});

节流(throttling)

节流:规定在一个单位时间内,只能触发一次函数。如果在这个单位时间内多次触发,只有一次生效。

应用场景

  • 滚动加载更多
  • 页面缩放
  • 鼠标移动
js
function debounce(fn, delay) {
  let timer = null;
  return function () {
    const context = this;
    const args = arguments;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, delay);
  };
}

手写节流函数

js
function throttle(fn, delay) {
  let timer = null;
  return function () {
    const context = this;
    const args = arguments;
    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(context, args);
        timer = null;
      }, delay);
    }
  };
}

loadash节流

js
import _ from 'lodash';

const searchInput = document.getElementById('search');
const resultDiv = document.getElementById('result');

const fetchResults = _.throttle(function(query) {
    // 模拟 API 请求
    resultDiv.innerText = `Searching for: ${query}`;
}, 300);

searchInput.addEventListener('input', (event) => {
    fetchResults(event.target.value);
});

实际案列和应用

js
<script>
    const scrollMessage = document.getElementById('scrollMessage');

    // 使用 Lodash 的 throttle 函数
    const handleScroll = _.throttle(() => {
        const time = new Date().toLocaleTimeString();
        scrollMessage.innerText = `Scrolled at: ${time}`;
    }, 500); // 每 500 毫秒执行一次

    window.addEventListener('scroll', handleScroll);
</script>

Released under the MIT License.