前端面试之防抖节流(二)

前言

大家好,作者之前在防抖节流(一)中介绍了一下防抖节流中的防抖,详细阐述了它的应用以及实现代码,这篇文章将要介绍一下它的好兄弟--节流。

什么是节流

那么什么是节流呢?

节流(throttle)是通过限制函数执行的频率,在一定时间内只执行一次,以减少资源消耗或优化性能。

它在页面中的效果是这样的:

注意看控制台:在用户输入时,无论用户输入的频率如何,节流帮我们控制了让输入框内容的输出只有在一秒内才能输出一次。

大家都打过fps游戏吧,不论你的鼠标左键点击多少次,最终枪械的输出次数只取决于它的射速,这就类似于节流的效果。

为什么要节流?

那么为什么要节流呢?

有一些典型的应用场景:

  1. 滚动事件(scroll)

    • 问题:滚动页面时会高频触发 scroll 事件,如果回调函数涉及 DOM 计算、动画等操作,会导致卡顿。
    • 节流作用:限制为每 100ms 执行一次,减少不必要的计算。
  2. 窗口调整(resize)

    • 问题:拖拽调整窗口大小时,resize 事件会连续触发,若回调函数需要重新布局页面,可能引发性能瓶颈。
    • 节流作用:确保只在调整结束后或固定间隔执行一次布局计算。
  3. 按钮防连点(点击提交)

    • 问题:用户快速点击提交按钮时,可能发送多次重复请求。
    • 节流作用:限制点击间隔(如 1 秒内只能提交一次),避免重复请求。

节流的实现

接下来看看节流的实现吧

节流的实现代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <input type="text" id="inputC" />
    <script>
        let inputC = document.getElementById('inputC');
        const ajax = function(content) { //被节流的函数
            console.log("ajax request" + content)
        }

        function throttle(fn,delay) {
            let last,
                deferTimer;

            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,1000);

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

了解过上一篇介绍防抖的实现代码的朋友们看到这里会发现,防抖的代码结构和节流很类似,是的,它们都是用高阶函数实现+闭包特性实现的,下面是详细解读

  • (一)定义ajax函数
js 复制代码
const ajax = function(content) { //被节流的函数
    console.log("ajax request" + content)
}

ajax 是一个模拟的请求函数,在实际应用中可能是 fetchXMLHttpRequest 请求。


  • (二)实现throttle节流函数
js 复制代码
function throttle(fn, delay) {
    let last, deferTimer; // 记录上次执行时间、定时器

    return function(args) {
        let that = this; // 保存 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); // 立即执行函数
        }
    }
}

这里是节流实现的核心部分:

  1. last :记录上次执行 fn 的时间戳。

  2. deferTimer :存储 setTimeout 的 ID,用于清除未执行的延迟调用。

  3. now :获取当前时间戳(+new Date() 转化为number类型,方便等下计算)。

  4. 节流判断

if (last && now < last + delay)

如果 last 存在(非首次调用),并且当前时间距离上次调用时间小于 delay(仍在节流间隔内),则:

go 复制代码
清除之前的 `setTimeout`(避免堆积多个延迟调用)。
重新设置一个 `setTimeout`,在 `delay` 时间后执行 `fn`。

else

go 复制代码
如果不在节流间隔内(首次调用或间隔已过),则:
    立即执行 `fn`,并更新 `last` 时间戳。

  • (三)应用节流函数
js 复制代码
let throttleAjax = throttle(ajax, 1000); // 1秒内只执行一次
inputC.addEventListener('keyup', function(e) {
    throttleAjax(e.target.value); // 传入输入框的值
});

throttle(ajax, 1000) :生成一个节流版本的 ajax 函数,确保 1 秒内最多执行一次。

keyup 事件监听

go 复制代码
每次输入时,调用 `throttleAjax`,传入输入框的值。

如果用户在 1 秒内连续输入,`ajax` 不会立即触发,而是:

    第一次输入时立即执行 `ajax`。
    后续输入会进入 `setTimeout`,并在 1 秒后执行(如果期间没有新的输入)。

执行流程示例

假设用户快速输入 abc

  1. 输入 a

    • last 未定义 → 立即执行 ajax("a"),并记录 last = now
  2. 输入 b(0.5 秒后)

    • now < last + 1000(仍在 1 秒内)→ 清除之前的 setTimeout,重新设置 1 秒后执行 ajax("b")
  3. 输入 c(0.8 秒后)

    • now < last + 1000(仍在 1 秒内)→ 再次清除 setTimeout,重新设置 1 秒后执行 ajax("c")
  4. 最终结果

    • ajax("a") 立即执行。
    • ajax("c") 在 1 秒后执行(b 被覆盖)。

总结

上面就是关于节流知识的全部内容了,希望该文章对你有帮助!

相关推荐
岁忧1 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
一斤代码2 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子2 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子3 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina3 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路3 小时前
React--Fiber 架构
前端·react.js·架构
coderlin_4 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
伍哥的传说4 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409194 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app