JavaScript 防抖

本文深入探讨了防抖技术在处理高频事件如窗口调整大小、滚动、鼠标移动等场景中的应用,通过不同版本的函数实现,逐步解析如何避免事件过度触发导致的性能问题。

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

参考:https://github.com/mqyqingfeng/Blog/issues/22

应用:防抖主要用来解决高频事件短时间高频触发,带来的一系列的bug,全部代码和解释经过验证,结合自己的理解

高频事件:

  1. window 的 resize、scroll
  2. mousedown、mousemove
  3. keyup、keydown

demo:主要修改事件绑定的触发函数,一步一步深入理解

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <title>防抖</title>
    <style>
        #container {width: 100%;height: 200px;line-height: 200px;text-align:center;color: #fff;background-color: #444;font-size: 30px;}
    </style>
</head>
<body>
    <div id="container"></div>
    <script>
        var count = 1;
        var container = document.getElementById('container');
        function getUserAction() {
            container.innerHTML = count++;
        };
        container.onmousemove = getUserAction;
    </script>
</body>
</html>

版本一:每次次事件触发,都会清除上次事件的定时器,达到连续触发,只执行一次的效果

function debounce(func, wait) {
    var timeout;
    return function () {
        clearTimeout(timeout)//每次次事件触发,都会清除上次事件的定时器,达到连续触发,只执行一次的效果
        timeout = setTimeout(func, wait);
    }
}
container.onmousemove = debounce(getUserAction, 1000);//后续这一行会省略

版本二:为了解决在getUserAction使用this,如果使用debounce,那么this就会指向window

function debounce(func, wait) {
    var timeout;
    return function () {
        var context = this;//保存事件this
        clearTimeout(timeout)
        timeout = setTimeout(function () {
            func.apply(context)//重新绑定this
        }, wait);
    }
}

版本三:重新绑定事件对象

function debounce(func, wait) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;//获取return 函数的参数
        clearTimeout(timeout)
        timeout = setTimeout(function () {
            func.apply(context, args)//重新调用函数时指定参数
        }, wait);
    }
}

版本四:立即执行,事件发生后,函数立即执行

function debounce(func, wait, immediate) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;
        if (timeout) clearTimeout(timeout);//
        if (immediate) {//立即执行逻辑
            //--------------构成是是否判断----------------
            var callNow = !timeout;
            timeout = setTimeout(function () {
                timeout = null;//连续事件触发,下次能执行时间会一致往后移wait,除非等待时间结束后再触发
            }, wait)
            //--------------构成是是否判断end----------------
            if (callNow) func.apply(context, args)//是第一次触发
        }
        else {//非立即执行
            timeout = setTimeout(function () {
                func.apply(context, args)
            }, wait);
        }
    }
}

版本四.1 返回值

function debounce(func, wait, immediate) {
    var timeout, result;
    return function () {
        var context = this;
        var args = arguments;
        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)//只能立即执行才能有返回值
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;//在这里返回,非立即执行会报undefined
    }
}

版本四.2  取消延长wait

function debounce(func, wait, immediate) {
    var timeout, result;
    var debounced = function () {//通过对象保存机制
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) result = func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
        return result;
    };
    debounced.cancel = function() {
        clearTimeout(timeout);
        timeout = null;//这一步就打断了连续触发延长wait的机制
    };
    return debounced;//返回对象
}

使用方法:

var count = 1;
var container = document.getElementById('container');

function getUserAction(e) {
    container.innerHTML = count++;
};

var setUseAction = debounce(getUserAction, 10000, true);

container.onmousemove = setUseAction;

document.getElementById("button").addEventListener('click', function(){
    setUseAction.cancel();
})

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值