JS进阶 | 函数的节流

1,292 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 9 天,点击查看活动详情

提到防抖和节流你会想到什么?表单的提交、模糊搜索、输入框内容校验、窗口尺寸的变化...在短时间内大量触发同一事件,不仅会使浏览的负担加重,影响性能,还会有不好的用户体验。

而防抖和节流正是解决此问题的方案之一,在前端面试中也高频出现的问题。

一般防抖会和节流进行对比记忆:

  • 防抖:当用户触发某个事件的操作过于频繁,只执行最后一次对事件的操作
  • 节流:当持续触发事件时,n秒内只调用一次事件处理函数,在这段时间内不会重新执行事件。

关于防抖,可参考全面面的文章:JS进阶 | 关于防抖

节流的实现

时间戳法

核心的思路就是使用闭包,利用时间戳的差值来决定什么时候执行函数。

  • 设定 prev 变量,用来记录最近一次触发函数的时间,初始为 0(这里不能像防抖一样设置成 null,因为后面需要参与计算)
  • 闭包中定义一个 now 变量,存储当前的时间戳
  • 如果当前时间 now 大于上一次触发的时间 prev(第一次触发事件也会是大于的关系),执行对应的方法,并将 last 设为当前最新的时间
function throttle(Fn, interval) {
    var prev = 0;
    return function () {
        var now = new Date().getTime();
        if (now - prev > interval) {
            Fn.apply(this, arguments);
            prev = now;
        }
    }
}

定时器法

  • 设定一个空的定时器
  • 当定时器为空时,按照一定的时间频率触发函数执行,执行后清空定时器(注:这里是和防抖的实现不同的地方)
var throttle = function(func, delay) {
    var timer = null;
    return function() {
        if (!timer) { //  timer 为 null
            timer = setTimeout(function() {
                func.apply(this, arguments);
                timer = null; // 每触发一次事件,就清空定时器
            }, delay);
        }
    }
}

节流的升级

按照上述代码运行后,会发现一个问题:节流函数的最后一次不会执行(无法满足 now - last > interval 的条件)。如果想要最节流函数的后一次也执行,时间戳+定时器的组合使用可以实现。

image.png