js 中 函数的防抖和节流

防抖和节流是JavaScript中用于优化性能的技术,主要应用于处理高频事件,如scroll、resize等。防抖函数确保在一系列连续触发后只执行最后一次,而节流函数则保证以固定频率执行。文章通过代码示例和滚动事件的应用展示了防抖和节流的实现与区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

防抖和节流

什么是防抖和节流
防抖和节流,都是为了防止短时间内高频繁调用同一接口的方法。

防抖

核心:设置延时器,短时间高频率触发只有最后一次触发成功
解释:如果一个事件被频繁执行多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数,只执行最后触发的一次。函数防抖可以把多个顺序的调用合并成一次。

无论你如何乱点,也只有你停止点击的最后一次会请求成功。

缺点:响应时间太久。

实现函数防抖

function debounce(fn, wait) {
        var timer = null;
        // 返回函数对debounce作用域形成闭包
        return function () {
            var context = this
            var args = arguments
            if (timer) {
                // 事件被触发,清除timer并重新开始计时
                clearTimeout(timer);
                timer = null;
            }
            timer = setTimeout(function () {
                fn.apply(context, args)
            }, wait)
        }
    }

    var fn = function () {
        console.log('boom')
    }

    setInterval(debounce(fn, 500), 1000) // 第一次在1500ms后触发,之后每1000ms触发一次

    setInterval(debounce(fn, 2000), 1000) // 不会触发一次(把函数防抖看出技能读条,如果读条没完成就用技能,便会失败而且重新读条)

节流

核心:设置状态锁,短时间高频率触发只有第一次触发成功
解释:如果一个事件被频繁触发多次,节流函数可以按照固定的频率去执行相应的事件处理方法。函数节流保证一个事件一定事件内只能执行一次。

实现函数节流

利用时间戳实现
// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {
  // 上一次执行 fn 的时间
  let previous = 0
  // 将 throttle 处理结果当作函数返回
  return function(...args) {
    // 获取当前时间,转换成时间戳,单位毫秒
    let now = +new Date()
    // 将当前时间和上一次执行函数的时间进行对比
    // 大于等待时间就把 previous 设置为当前时间并执行函数 fn
    if (now - previous > wait) {
      previous = now
      fn.apply(this, args)
    }
  }
}

// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)
利用定时器实现
var key = false
    btn.onclick = function () {
        // if (key == false) {
        if (!key) {
            console.log('请求');
            key = true
            setTimeout(function () {
                key = false
            }, 5000)
        }
    }
实例(scroll 事件)

css部分

<style>
        .wrap {
            width: 200px;
            height: 330px;
            margin: 50px;
            margin-top: 200px;
            position: relative;
            float: left;
        }

        .header {
            width: 100%;
            height: 30px;
            background-color: #a8d4f4;
            text-align: center;
            line-height: 30px;
        }

        .container {
            background-color: darkseagreen;
            box-sizing: content-box;
            width: 200px;
            height: 300px;
            overflow: scroll;
            position: relative;
        }

        .content {
            width: 140px;
            height: 800px;
            margin: auto;
            background-color: cadetblue;
        }
    </style>

html部分

<body>
    <div class="wrap">
        <div class="header">滚动事件:普通</div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="header">滚动事件:<strong>加了函数防抖</strong></div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
    <div class="wrap">
        <div class="header">滚动事件:<strong>加了函数节流</strong></div>
        <div class="container">
            <div class="content"></div>
        </div>
    </div>
</body>

js部分

 let els = document.getElementsByClassName('container');
        let count1 = 0,
            count2 = 0,
            count3 = 0;
        const THRESHOLD = 200;

        els[0].addEventListener('scroll', function handle() {
            console.log('普通滚动事件!count1=', ++count1);
        });
        els[1].addEventListener('scroll', debounce(function handle() {
            console.log('执行滚动事件!(函数防抖) count2=', ++count2);
        }, THRESHOLD));
        els[2].addEventListener('scroll', throttle(function handle() {
            console.log(Date.now(), ', 执行滚动事件!(函数节流) count3=', ++count3);
        }, THRESHOLD));

        // 函数防抖
        function debounce(fn, delay, scope) {
            let timer = null;
            let count = 1;
            return function () {
                let context = scope || this,
                    args = arguments;
                clearTimeout(timer);
                console.log(Date.now(), ", 触发第", count++, "次滚动事件!");
                timer = setTimeout(function () {
                    fn.apply(context, args);
                    console.log(Date.now(), ", 可见只有当高频事件停止,最后一次事件触发的超时调用才能在delay时间后执行!");
                }, delay);
            }
        }

        // 函数节流
        function throttle(fn, threshold, scope) {
            let timer;
            let prev = Date.now();
            return function () {
                let context = scope || this,
                    args = arguments;
                let now = Date.now();
                if (now - prev > threshold) {
                    prev = now;
                    fn.apply(context, args);
                }
            }
        }

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

防抖和节流区别

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会真正执行一次事件处理函数,而函数防抖只是在最后一次触发后才会执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值