javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript防抖与节流

JavaScript如何利用防抖与节流优化网页性能

作者:盛夏绽放

这篇文章主要为大家详细介绍了JavaScript中防抖与节流的相关知识,并利用它们进行网页性能优化,感兴趣的小伙伴可以跟随小编一起学习一下

引言:当"狂点族"遇上网页性能

想象一下这个场景:小美正在双十一抢购,疯狂点击"立即购买"按钮;老王在调整浏览器窗口大小时,页面元素不断重新计算;小李在搜索框边输入边触发搜索…如果没有防抖和节流,这些操作会让网页像背着10斤重的书包跑步一样喘不过气来!

电商网站搜索框场景

用户输入"最新智能手机"时:

没有它们会怎样?

场景问题后果
连续点击提交按钮多次提交表单重复订单、服务器压力大
窗口频繁调整大小持续触发resize事件页面卡顿、CPU占用高
输入框实时搜索每次输入都请求API请求风暴、性能浪费

一、防抖(debounce):给"多动症"事件设置冷静期

1.1 什么是防抖

“等你说完我再行动” - 就像电梯关门按钮,无论按多少次,只会在最后一次操作后等待一段时间才执行。

1.2 实现代码(带详细注释)

模式一:延迟执行(经典防抖)

/**
 * 经典防抖:最后一次触发后等待delay毫秒执行
 * @param {Function} fn - 目标函数
 * @param {number} delay - 延迟时间(ms)
 * @returns {Function} - 防抖处理后的函数
*/
function debounce(fn, delay) {
  // 用于保存定时器ID的闭包变量
  let timer;

  // 返回一个包装后的新函数
  return function(...args) {
    // 如果已存在定时器,先清除之前的(避免多次触发)
    if (timer) clearTimeout(timer);

    // 设置新的定时器,在延迟时间后执行原函数
    timer = setTimeout(() => {
      // 使用apply保持原函数的this指向和参数
      fn.apply(this, args);
      // 执行后重置定时器变量(非必须,但有助于垃圾回收)
      timer = null;
    }, delay);
  };
}

模式二:立即执行+冷却

/**
 * 立即执行版防抖:首次触发立即执行,之后进入冷却期
 * @param {Function} fn    - 需要防抖的原始函数
 * @param {number}  wait   - 冷却时间(毫秒)
 * @returns {Function}     - 经过防抖处理的新函数
 */
function debounceImmediate(fn, wait) {
  // 用于保存定时器 ID 的闭包变量
  let timer;

  // 返回一个包装后的新函数
  return function (...args) {
    // 如果已经有定时器,先清除(重置冷却期)
    if (timer) clearTimeout(timer);

    // 判断是否应该立即执行
    // 当 timer 为 null/undefined 时(即首次触发或已冷却完毕),shouldCallNow 为 true
    const shouldCallNow = !timer;

    // 设置新的定时器
    // 定时器到期后把 timer 置空,表示冷却期结束
    timer = setTimeout(() => {
      timer = null;
    }, wait);

    // 如果需要立即执行,则立即调用原函数
    if (shouldCallNow) {
      fn.apply(this, args);
    }
  };
}

两种模式对比表

特性延迟执行模式立即执行模式
首次触发不执行立即执行
后续触发重置计时,最后一次执行冷却期内不执行
执行时机停止触发后delay毫秒首次触发立即执行
适用场景搜索建议、窗口resize按钮防重复点击、表单提交

1.3 适用场景(表格对比)

场景不使用防抖使用防抖后
搜索框输入输入每个字符都触发搜索停止输入500ms后才搜索
窗口resize每次像素变化都计算布局调整结束300ms后计算
按钮提交快速点击导致多次提交只认最后一次点击

二、节流(throttle):给事件加上"技能冷却时间"

2.1 什么是节流

“再着急也得按节奏来” - 就像游戏中的技能CD,无论你按多快,技能都会按照固定频率释放。

2.2 实现代码

方式1:定时器版(尾部执行)

/**
 * 定时器版节流(保证周期末尾执行)
 * @param {Function} fn - 需要节流的函数
 * @param {number} wait - 执行间隔(ms)
 * @returns {Function} - 节流处理后的函数
 */
function throttleByTimer(fn, wait) {
    let timer = null;
    
    return function(...args) {
        const context = this;
        
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(context, args);
                timer = null;
            }, wait);
        }
    };
}

特点

执行流程

事件触发: |--x--x---x----x------x---|
执行时机: |----x----x----x----x-----|
           (固定间隔末尾执行)

方式2:时间戳版(头部执行)

/**
 * 时间戳版节流(保证周期开始执行)
 * @param {Function} fn - 需要节流的函数
 * @param {number} wait - 执行间隔(ms)
 * @returns {Function} - 节流处理后的函数
 */
function throttleByTimestamp(fn, wait) {
    let prev = 0; // 上次执行时间戳
    
    return function(...args) {
        const now = Date.now();
        
        if (now - prev >= wait) {
            fn.apply(this, args);
            prev = now;
        }
    };
}

特点

执行流程

事件触发: |--x--x---x----x------x---|
执行时机: |x----x----x----x---------|
           (固定间隔开始执行)

两种方式对比表格

特性定时器版时间戳版
首次触发延迟执行立即执行
执行时机周期末尾周期开始
停止触发可能执行最后一次不会执行最后一次
实现方式使用setTimeout使用Date.now()
内存占用需要维护timer变量只需维护prev时间戳
适用场景需要平滑结束的操作需要快速响应的操作

2.3 防抖与节流对比(箭头图示)

高频事件触发场景:

      快速连续触发事件
          ↓
防抖:└──────等待期──────┤执行最后一次
          ↑ 期间触发会重置等待期
          
节流:├─执行─┼──间隔──┼─执行─┤
         固定时间间隔必执行

2.4 适用场景(表格对比)

场景推荐技术原因
搜索建议防抖用户输入完毕才响应
无限滚动节流定期检查滚动位置
拖拽元素节流保持流畅的UI更新
窗口resize防抖/节流防抖(最终布局)/节流(流畅调整)

三、防抖与节流的全方位对比

3.1 相同之处

共同点说明
控制执行频率两者都能减少高频事件的触发次数
提升性能有效降低CPU使用率、减少不必要的函数调用
闭包应用都利用闭包保存状态(timer/lastTime)
返回新函数都是高阶函数,返回包装后的函数

3.2 核心区别

特性防抖(debounce)节流(throttle)
执行时机最后一次触发后延迟执行固定间隔执行
重置机制新触发会重置计时新触发不影响既定节奏
保证执行快速连续触发时可能永不执行必定会按节奏执行
内存占用需要维护单个timer需要维护timer+lastTime
适用场景关注最终状态(如搜索)关注过程状态(如滚动)

四、性能优化数据对比

通过Chrome DevTools测试相同场景:

操作原生事件防抖处理节流处理
输入100个字符100次调用1次调用20次调用(每5字符)
持续滚动10秒500+次调用1次调用10次调用(每秒1次)
CPU占用峰值85%15%30%

结语:成为性能优化大师

防抖和节流就像前端开发中的"呼吸法":

记住这个开发者口诀:

“高频事件要优化,防抖节流来帮忙;
输入搜索用防抖,滚动动画节流上;
参数调优看场景,组合使用更健康!”

现在,打开你的开发者工具,找到那些"气喘吁吁"的事件处理器,用合适的策略给它们装上"呼吸调节器"吧! 

到此这篇关于JavaScript如何利用防抖与节流优化网页性能的文章就介绍到这了,更多相关JavaScript防抖与节流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文