防抖与节流和其他实现方式

24 阅读4分钟

场景

  1. 边输入边搜索并会发送请求到后台,第一次请求时,第二次还在请求,但是不想要第一次请求,想要第二次请求的数据,这应该怎么实现
  2. 应该如何实现呢,首选的就是防抖节流去实现,那么仔细想想,除了防抖和节流还有什么方式可以实现

分析

1. 是什么

防抖

  • 顾名思义,我们可以将防抖理解为是防止抖动。当我们在频繁地触发一个事件时,会引起不必要的性能损失,那么我们需要做的是让事件在停止触发后再触发,以此减少性能损失。
  • 防抖就是要延迟执行,我们一直操作触发事件并且不执行,只有当停止操作后等才会执行。
  • 防抖函数的作用是控制函数在一定时间内的执行次数。简单点说就是通过防抖函数让某个触发事件在 n 秒内只会被执行一次。
  • 总的来说,如果一个函数持续地、频繁地触发,那么只在它结束后过一段时间才开始执行。换句话说,如果你持续触发事件,那么防抖函数将不会执行,只有当你停止触发事件后,它才会在指定的延迟时间后执行。
  • 场景:防止例如用户在输入框中连续输入时发送过多的Ajax请求等情况。
  • 防抖 就像是你在等电梯一样。当你按下电梯按钮后,电梯并不会立刻来,而是等你停止按按钮一段时间后,电梯才开始运行。在编程中,防抖的原理是当事件被触发后,等待一段时间,如果这段时间内没有再次触发事件,那么才执行相应的操作。这样可以避免频繁触发事件导致频繁执行操作的问题。比如,在输入框输入文字时,防抖可以确保只有在用户停止输入一段时间后才会执行搜索或其他操作

节流

  • 节流是指绑定事件后,通过动作触发事件,在这段时间内,如果动作又发生,忽略该动作,一直到事件执行完后才能重新触发。通俗的说就是控制高频执行的次数。
  • 节流函数的作用是在一个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效
  • 总的来说,如果你持续触发事件,每隔一段时间,事件处理函数只执行一次。这有助于限制一些处理函数的执行频率,
  • 场景:滚动事件、窗口大小调整事件等。
  • 节流 就像是水龙头一样。当你打开水龙头时,水不会立刻流出,而是以一个固定的速率流出。在编程中,节流的原理是设定一个时间间隔,在这个时间间隔内,无论事件触发多少次,只会执行一次操作。比如,在滚动页面时,节流可以确保在一定时间间隔内只触发一次页面滚动事件,从而减少事件处理的频率,提高性能。

简而言之,防抖是在事件停止触发后延迟执行函数,而节流是按照固定的时间间隔执行函数。

2. 怎么用

  1. 防抖(简单版本)
// 防抖(简单版本)
// 防抖函数
function debounce(func, wait) {
  let timeout;
  return function() {
    const context = this;
    const args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      func.apply(context, args);
    }, wait);
  };
}

  1. 防抖(立即执行版本)
// 防抖(立即执行版本)
function debounce(fn, wait) {
    let timer = null
    return function () {
        let args = arguments
        let now = !timer
        timer && clearTimeout(timer)
        timer = setTimeout(() => {
            timer = null
        }, wait)
        if (now) {
            fn.apply(this, args)
        }
    }
}
  1. 节流(定时器版本)
// 节流(定时器版本)
function throttle(fn, wait) {
    let timer = null
    return function () {
        let context = this
        let args = arguments
        if (!timer) {
            timer = setTimeout(() => {
                timer = null
                fn.apply(context, args)
            }, wait)
        }
    }
}
  1. 触发他们
<style>
  html{
    height: 500vh;
  }
</style>
<body>
  
</body>
<script src="./debounce.js"></script>
<script src="./throttle.js"></script>
<script>
  // 防抖示例
const debouncedSearch = debounce(function() {
  console.log('防抖搜索');
}, 500);
window.addEventListener('scroll', debouncedSearch);

// 节流示例
const throttledScroll = throttle(function() {
  console.log('节流行为');
}, 500);
window.addEventListener('scroll', throttledScroll);

</script>

3. 其他实现方式

针对这个场景,你可以在发送请求之前检查当前输入框的值是否发生了变化。如果输入框的值发生了变化,则取消之前的请求,并发送一个新的请求,以确保获取到最新的数据。

下面是一个示例代码,演示了如何在输入框值变化时取消之前的请求,并发送新的请求:

let lastRequest = null;

function sendRequest() {
    // 获取输入框的值
    const input = document.getElementById('dropdown').value;
    
    // 取消之前的请求
    if (lastRequest) {
        lastRequest.abort();
    }
    
    // 发送新的请求
    lastRequest = $.ajax({
        url: 'your_backend_endpoint',
        type: 'GET',
        data: { query: input },
        success: function(response) {
            // 处理返回的数据
            console.log(response);
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.error('Error:', errorThrown);
        }
    });
}

在这个示例中,sendRequest() 函数用于发送请求。在每次调用该函数之前,会检查是否存在之前的请求(lastRequest),如果存在,则取消之前的请求。然后,发送新的请求,以确保获取最新的数据。