节流(Throttle):给频繁触发的事件装上"冷却时间"

大家好,我是你们的老朋友FogLetter。今天我们要聊一个在前端性能优化中非常重要的概念------节流(Throttle)。如果你曾经遇到过页面因为频繁触发事件而卡顿的情况,那么这篇文章就是为你准备的!

什么是节流?

节流(Throttle)是一种限制函数执行频率的技术,它确保一个函数在固定的时间间隔内最多只执行一次。想象一下,这就像是给你的函数装上了一个"冷却时间",无论事件触发多么频繁,函数都会按照固定的节奏执行。

节流的核心思想:每隔单位时间内只执行一次,保证在一段时间间隔内一定会执行一次。

为什么需要节流?

在实际开发中,我们经常会遇到一些高频触发的事件:

  1. scroll 事件:滚动页面时频繁触发
  2. resize 事件:窗口大小改变时触发
  3. mousemove 事件:鼠标移动时触发
  4. keyup/keydown 事件:键盘输入时触发

如果这些事件的处理函数执行复杂的操作(如DOM操作、计算、网络请求等),频繁触发会导致:

  • 页面重绘重排次数过多
  • JavaScript引擎负担过重
  • 最终导致页面卡顿、不流畅

节流的价值:没有必要以scroll的频率去触发处理函数,我们只需要保证在一定时间内至少执行一次即可。

节流 vs 防抖

很多同学容易混淆节流和防抖,让我们先搞清楚它们的区别:

特性 防抖 (Debounce) 节流 (Throttle)
执行时机 事件停止后延迟执行 固定时间间隔执行
执行次数 只执行最后一次 均匀执行多次
适用场景 搜索建议、窗口resize 滚动加载、游戏中的按键处理
类比 电梯门关闭(等人进完) 地铁发车(定时出发)

简单记忆

  • 防抖:频繁触发 > delay 也不一定会执行成功,后面触发会将前面的清除,要停下来才会执行最后一次
  • 节流:每隔单位时间内一定执行一次

节流的实现原理

让我们通过一个实际的例子来理解节流的实现:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流实现示例</title>
</head>
<body>
    <input type="text" id="inputC">
    <script>
        let inputC = document.getElementById('inputC');
        const ajax = function(content) { // 被节流的函数
            // 模拟网络请求
            console.log("发送请求:", content)
        }

        function throttle(fn, delay) {
            let last, // 上一次的执行时间
                deferTimer; // timeout id
            return function (args) {
                let that = this; // 闭包的应用场景
                let now = +new Date(); // 类型转换
                if(last && now < last + delay) {
                    clearTimeout(deferTimer) // 此处不是单纯的节流,而是带有尾随执行的节流
                    deferTimer = setTimeout(function() {
                        last = now;
                        fn.call(that, args)
                    }, delay)
                } else {
                    last = now;
                    fn.call(that, args)
                }
            }
        }

        let throttleAjax = throttle(ajax, 200);
        inputC.addEventListener('keyup', function(e) {
            throttleAjax(e.target.value)
        })
    </script>
</body>
</html>

代码解析

  1. 闭包的应用throttle 函数返回一个新函数,这个新函数能够访问 lastdeferTimer 变量,这就是闭包的魔力。

  2. 时间控制

    • last 记录上一次执行的时间
    • now 获取当前时间
    • 如果距离上次执行时间小于设定的 delay,就清除之前的定时器并重新设置
    • 否则立即执行函数并更新 last
  3. this绑定 :使用 fn.call(that, args) 确保函数执行时的上下文正确

节流的应用场景

1. 滚动加载更多

javascript 复制代码
window.addEventListener('scroll', throttle(function() {
    if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - 500) {
        // 加载更多内容
        loadMoreItems();
    }
}, 200));

2. 游戏中的按键处理

javascript 复制代码
document.addEventListener('keydown', throttle(function(e) {
    if (e.key === 'ArrowRight') {
        player.moveRight();
    }
}, 100));

3. 窗口大小调整

javascript 复制代码
window.addEventListener('resize', throttle(function() {
    updateLayout();
}, 250));

4. 鼠标移动事件

javascript 复制代码
element.addEventListener('mousemove', throttle(function(e) {
    updateTooltipPosition(e.clientX, e.clientY);
}, 50));

闭包在节流中的关键作用

你可能注意到了,节流的实现离不开闭包。闭包在这里发挥了几个关键作用:

  1. 保存状态lasttimer 变量被闭包保存,使得每次调用都能记住之前的状态
  2. 私有化变量:这些变量对外部不可见,避免了全局污染
  3. 维持函数上下文 :通过闭包保存 this 值,确保回调函数执行时的上下文正确

关于闭包的其他应用场景,我在之前的笔记中已经详细讨论过,包括:

  • 防抖(debounce)实现
  • 绑定上下文的三种方式(箭头函数、bind、that = this)
  • 事件监听器
  • 记忆函数
  • 柯里化
  • 立即执行函数(IIFE)

性能优化小贴士

  1. 选择合适的节流时间:不是所有场景都适合200ms,根据实际需求调整

    • 动画效果:16ms(60fps)或33ms(30fps)
    • 用户输入:100-200ms
    • 滚动事件:50-100ms
    • 窗口resize:250ms
  2. 避免过度节流:有些事件需要即时响应,过度节流会影响用户体验

总结

节流是一种强大的性能优化技术,它能有效控制高频事件的触发频率,避免不必要的性能开销。通过本文,你应该已经掌握了:

  1. 节流的基本概念和实现原理
  2. 节流与防抖的区别
  3. 闭包在节流实现中的关键作用

记住,性能优化是一门平衡的艺术,既要保证流畅性,又不能牺牲用户体验。节流只是众多优化手段中的一种,合理运用才能发挥最大效果。

如果你觉得这篇文章有帮助,别忘了点赞收藏!

相关推荐
teeeeeeemo14 分钟前
如何做HTTP优化
前端·网络·笔记·网络协议·http
范范之交16 分钟前
JavaScript基础语法two
开发语言·前端·javascript
界面开发小八哥1 小时前
DevExtreme Angular UI控件更新:引入全新严格类型配置组件
前端·ui·界面控件·angular.js·devexpress
bitbitDown1 小时前
重构缓存时踩的坑:注释了三行没用的代码却导致白屏
前端·javascript·vue.js
xiaopengbc1 小时前
火狐(Mozilla Firefox)浏览器离线安装包下载
前端·javascript·firefox
用户016523844411 小时前
Webpack5 入门与实战,前端开发必备技能无密
前端
小高0071 小时前
🔥🔥🔥前端性能优化实战手册:从网络到运行时,一套可复制落地的清单
前端·javascript·面试
古夕1 小时前
my-first-ai-web_问题记录01:Next.js的App Router架构下的布局(Layout)使用
前端·javascript·react.js
Solon阿杰1 小时前
solon-flow基于bpmnJs的流程设计器
javascript·bpmn-js
Solon阿杰1 小时前
前端(react/vue)实现全景图片(360°)查看器
javascript·vue.js