一个简单的节流性能优化案例 | 豆包MarsCode AI 刷题

119 阅读3分钟

节流(Throttle)是一种常用的前端性能优化手法,他的主要目的是控制频繁触发的事件

在前端中,有些事件会频繁触发,如果每次事件触发都执行一些复杂的操作,会导致页面变得卡顿,影响用户体验。而通过节流技术,可以控制事件的触发频率,从而减少不必要的操作,提高页面性能和用户体验。

下面我们以鼠标移动这个事件为例,来说明节流的思路和效果

我们的demo代码如下:

    <script>
        // 节流函数
        function throttle(func, delay) {
            let lastCall = 0;
            return function(...args) {
                const now = new Date().getTime();
                if (now - lastCall >= delay) {
                    func.apply(this, args);
                    lastCall = now;
                }
            }
        }

        // 普通鼠标移动处理
        function handleNormalMouseMove(event) {
            ...
        }

        // 节流鼠标移动处理
        const handleThrottledMouseMove = throttle(function(event) {
            ...
        }, 200);

这是一个简单的节流方案,思路其实就是对原函数做一个装饰器,这个装饰器的作用是延迟函数的触发,以此达到减少函数触发频率的效果

上述代码中,throttle 函数接收两个参数:要节流的函数 fn 和节流延迟时间 delay,并返回一个新的函数。

每当新的 fn 被调用时,throttle 函数会记录当前时间 now。如果上一次调用 fn 的时间和 now 的时间差小于 delay,则会清除上一个定时器并再次设置一个新的定时器,以延迟调用 fn 函数。否则,直接调用 fn 函数。

这样做可以确保 fn 函数最多每隔 delay 毫秒被调用一次,以避免在高频事件中频繁执行代码导致的性能问题。

图片.png

效果如图所示,在相同的时间内,对于鼠标移动这个事件,普通的函数触发了1160次,而我们的节流版本仅仅触发了62次,对于位置来说,这个版本的节流函数并不能准确反馈最后一次鼠标所在位置,但用于说明节流的思想足够了。

此外,节流还有基于浏览器帧(RAF, request animation frame)和setTimeout的方法

// RAF节流装饰器
function rafThrottle(fn) {
    let rafId = null;
    return function(...args) {
        if (rafId === null) {
            rafId = requestAnimationFrame(() => {
                fn.apply(this, args);
                rafId = null;
            });
        }
    }
}

// setTimeout节流装饰器
function setTimeoutThrottle(fn, delay = 200) {
    let timer = null;
    return function(...args) {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, args);
                timer = null;
            }, delay);
        }
    }
}

setTimeout和之前的方法一样,都是设置时间延迟,

RAF方法则是自动匹配浏览器渲染机制,在浏览器绘制下一帧的时候执行原函数,以此来减少不必要的函数调用

图片.png

在这个示例中,RAF方法和普通事件效果一样,我们可以加上延迟机制,强行让函数慢下来

最后,我们使用chrome f12自带的开发者工具来看一下这个demo中各个节流方法的性能表现

图片.png

我们着重关注event log

打开一小段时间,观察鼠标移动后发生了什么,实际上可以看到delay和setTimeout是开销最小的两种节流方法,尤其是setTimeout,raf因为要request animation frame,反而自带一些固定的成本

综上,我们介绍了三大节流方法,这其实是前端入门必修课

节流(Throttle)本质上是通过延迟函数,来实现减少函数触发频率的技巧

使用方法类似装饰器,实现方法包括:

  • 手动判断now-lastCall > delay
  • setTimeout(推荐)
  • RAF 在某些情况可以比较使用

此外,我们也总结一下使用chrome f12来分析节流性能的基本流程

  • 打开chrome f12 devtools
  • 找到performance选项
  • 进入,点击record按钮
  • 运行一段时间
  • 点击stop
  • 打开一小段时间
  • 关注event log
  • 注意分析event log中代码的运作机制,找到你的分析目标