JavaScript 防抖与节流实战:原理、实现与优化

作者:缓存笔记时间:2026-10-23 11:30:37浏览:547

本文深入解析 JavaScript 中防抖(debounce)与节流(throttle)的核心原理及代码实现。通过对比时间戳与定时器两种节流方案,详细阐述如何结合两者优势,实现首次立即执行、间隔固定执行且最后一次也能触发的完整节流逻辑,有效解决高频事件导致的页面卡顿问题。

防抖与节流概述

在前端日常开发中,滚动等高频事件若频繁触发复杂计算的回调函数,极易引发页面卡顿。为优化性能,通常需要将多次调用合并为单次操作,JS 中这种优化手段被称为防抖(debounce)和节流(throttle)。

函数防抖实现

函数防抖

防抖机制要求:在持续触发事件的过程中,必须等待一段设定的时间且期间不再次触发,处理函数才会执行。若在延时结束前再次触发,则重新计时。换言之,若用户连续触发且间隔小于设定时间,防抖模式下最终仅执行最后一次触发。


function debounce(fn, wait) {
  var timeout = null;   //定义一个定时器
  return function() {
    if(timeout !== null) 
        clearTimeout(timeout); //清除这个定时器
    timeout = setTimeout(fn, wait); 
  }
}
// 处理函数
function handle() {
  console.log(Math.random()); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));

防抖与节流概述

如代码所示,持续触发 scroll 事件时,handle 函数仅在 1 秒内执行一次。滚动过程中未持续执行,从而有效降低了性能损耗。

函数节流原理

函数节流

节流机制要求:在持续触发事件时,保证在一定时间周期内只调用一次处理函数。即使用户连续触发且间隔小于设定值,节流模式也会每隔固定时间执行一次。

一句话总结防抖与节流的区别:防抖将多次执行合并为最后一次执行,而节流将多次执行转化为每隔一段时间执行一次。实现函数节流主要采用时间戳和定时器两种方法。

时间戳实现方案

例如


var throttle = function(func, delay) {
  var prev = Date.now();
  return function() {
    var context = this;  //this指向window
    var args = arguments;
    var now = Date.now();
    if (now - prev >= delay) {
      func.apply(context, args);
      prev = Date.now();
    }
  }
}
function handle() {
  console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

上述节流函数利用时间戳机制,使第一次滚动事件立即执行回调,此后每隔 1000ms 执行一次;在不足 1000ms 的时间窗口内,滚动事件不会触发执行。


var throttle = function(func, delay) {
  var timer = null;
  return function() {
    var context = this;
    var args = arguments;
    if (!timer) {
      timer = setTimeout(function() {
        func.apply(context, args);
        timer = null;
      }, delay);
    }
  }
}
function handle() {
  console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

定时器实现方案

事件触发时设置定时器,若未到1000ms则定时器为null,到达规定时间执行函数并清除定时器。首次触发事件后,需等待1000ms才执行函数,产生延迟效果,且此期间滚动事件不执行函数。 仅使用时间戳或定时器均有缺陷,期望首次触发立即执行,最后一次触发也能执行一次事件处理函数。


var throttle = function(func, delay) {
   var timer = null;
   var startTime = Date.now(); //设置开始时间
   return function() {
       var curTime = Date.now();
       var remaining = delay - (curTime - startTime); //剩余时间
       var context = this;
       var args = arguments;
       clearTimeout(timer);
       if (remaining <= 0) {   // 第一次触发立即执行
          func.apply(context, args);
          startTime = Date.now();
       } else {
          timer = setTimeout(func, remaining);  //取消当前计数器并计算新的remaining
       }
   }
}
function handle() {
   console.log(Math.random());
}
 window.addEventListener('scroll', throttle(handle, 1000));

防抖与节流概述

综合优化方案

单独使用时间戳或定时器均存在缺陷:时间戳方案首次执行但最后一次可能不执行,定时器方案最后一次执行但首次有延迟。理想状态是首次触发立即执行,且最后一次触发也能执行处理函数。通过引入开始时间 startTime、当前时间 curTime 和剩余时间 remaining,当 remaining 小于等于 0 时执行处理函数。这样既保证首次立即执行,又确保每隔 delay 时间执行一次;若未到时间,则在 remaining 后触发,保证最后一次也能执行。若在 remaining 时间内再次触发,则取消当前计数器并重新计算 remaining 时间。结合时间戳与定时器,实现了首次立即执行、间隔固定执行及最后一次执行的完整效果,可灵活应用于开发中。

注:防抖和节流能有效减少浏览器引擎损耗,防止页面堵塞卡顿,开发者应熟练掌握。感谢原作者的技术分享。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章