JavaScript 防抖与节流函数的原理、实现及适用场景详解

作者:闭包旅人时间:2026-10-24 13:26:25浏览:238

本文详细解析 JavaScript 中防抖(debounce)与节流(throttle)函数的实现原理。通过代码示例展示如何利用 setTimeout 控制函数执行频率,并解决 this 指向与参数传递问题。同时梳理了搜索输入、窗口缩放、滚动加载等典型应用场景,帮助开发者提升前端性能。

一、什么是函数防抖

函数防抖(debounce)的核心概念是:在事件触发后,设定一个 n 秒的等待窗口。如果在 n 秒内再次触发该事件,则重新计算并重置延迟执行的时间。只有当 n 秒内没有新的触发行为时,函数才会真正执行一次。

1、为什么需要函数防抖?

在前端开发中,resize、scroll、mousemove、mouseover 等事件极易被频繁触发。若不加限制,短时间内可能执行几十甚至几百次回调。特别是当回调内部涉及 DOM 操作时,会大量消耗计算机资源,导致页面运行缓慢,严重时甚至引发浏览器卡顿或崩溃。

2、函数防抖的要点

实现防抖的关键在于使用 setTimeout 来延迟执行目标代码。当方法被多次触发时,利用 clearTimeout 清除上一次的定时器,并重新开始计时。若在规定时间内未再触发新事件,则计时结束后执行目标代码。

3、函数防抖的实现


//HTML部分
 <div>
    账户:<input type="text" id="myinput">
</div>

//JS部分
function debounce(fun,wait=1500){//ES6语法 wait=1500 设置参数默认值,如果没有输入wait就会使用1500
        let timeout = null
        return function(){
            if(timeout){//如果存在定时器就清空
                clearTimeout(timeout)
            }
            timeout=setTimeout(function(){
                fun()
            },wait)
        }

    }
function testUname(){
    console.log("输入结束!")
}
document.getElementById('myinput').addEventListener('input',debounce(testUname,1000))

一、什么是函数防抖

上述代码展示了防抖函数的基本用法。只要每次输入的间隔大于一秒,就不会立即打印“输入结束!”,直到用户停止输入。这是因为每一次新的输入都会清除上一次的计时器,从而重置倒计时。

看到这里你以为就结束了吗?别急,让我们继续看:


//HTML部分
 <div>
    账户:<input type="text" id="myinput">
</div>

//JS部分
function debounce(fun,wait=1500){
        let timeout = null
        return function(){
            console.log(this)//<input id="myinput" type="text">
            console.log(arguments)//Arguments { 0: input, … }
            if(timeout){//如果存在定时器就清空
                clearTimeout(timeout)
            }
            timeout=setTimeout(function(){
                console.log(this)//Window
                console.log(arguments)//Arguments { … }
                fun()
            },wait)
        }

    }
function testUname(){
    console.log("输入结束!")
}
document.getElementById('myinput').addEventListener('input',debounce(testUname,1000))

无论是防抖还是节流,实现时都必须解决两个关键问题:this 的指向和 arguments 参数的传递。

如果没有特殊指定,setTimeout 和 setInterval 的回调函数中,this 默认指向 window。这是因为定时器方法定义在 window 对象下。然而,我们监听的是 input 输入框,通常希望定时器内的 this 指向该 input 元素,而非 window。

那么有什么方法可以改变this指向吗?

一种简单的办法就是我们可以用参数把定时器外层函数的this和arguments保存下来。然后再通过apply改变定时器要执行的函数fun的指向。


//JS部分
function debounce(fun,wait=1500){
            let timeout = null
            return function(){
                let _this = this
                let arg = arguments
                if(timeout){//如果存在定时器就清空
                    clearTimeout(timeout)
                }
                timeout=setTimeout(function(){
                    console.log(_this)//<input id="myinput" type="text">
                    console.log(arg)//Arguments { 0: input, … }
                    fun.apply(_this,arg)
                },wait)
            }
         
        }

一、什么是函数防抖

当然,你也可以用ES6的箭头函数新特性:箭头函数的 this 始终指向函数定义时的 this,而非执行时。箭头函数需要记着这句话:“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则 this 绑定的是最近一层非箭头函数的 this,否则,this 为 undefined”。

所以也可以这样写:


//JS部分
function debounce(fun,wait=1500){
            let timeout = null
            return function(){
                if(timeout){//如果存在定时器就清空
                    clearTimeout(timeout)
                }
                timeout=setTimeout(()=>{
                    console.log(this)//<input id="myinput" type="text">
                    console.log(arguments)//Arguments { 0: input, … }
                    fun.apply(this,arguments)
                },wait)
            }
         
        }

一、什么是函数防抖

4、函数防抖的使用场景

函数防抖一般用在什么情况之下呢?一般用在,连续的事件只需触发一次回调的场合。具体有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求;
  • 用户名、手机号、邮箱输入验证;
  • 浏览器窗口大小改变后,只需窗口调整完后,再执行 resize 事件中的代码,防止重复渲染。

二、什么是函数节流

概念: 限制一个函数在一定时间内只能执行一次。

举个栗子,坐火车或地铁,过安检的时候,在一定时间(例如10秒)内,只允许一个乘客通过安检入口,以配合安检人员完成安检工作。上例中,每10秒内,仅允许一位乘客通过,分析可知,“函数节流”的要点在于,在 一定时间 之内,限制 一个动作 只 执行一次 。

1、函数节流的要点

主要实现思路就是通过 setTimeout 定时器,通过设置延时时间,在第一次调用时,创建定时器,先设定一个变量,然后把定时器赋值给这个变量,再写入需要执行的函数。第二次执行这个函数时,会判断变量是否true,是则返回。当第一次的定时器执行完函数最后会设定变量为false。那么下次判断变量时则为false,函数会依次运行。目的在于在一定的时间内,保证多次函数的请求只执行最后一次调用。 这么看是不是有点看不懂?让我们来看代码:

2、函数节流的实现


//JS部分
function debounce(fun,wait=1000){//定时器方案
            let timer = null;//先设定一个变量
            return function(){
                if(!timer){//如果timer为null就进入
                    timer = setTimeout(function(){//然后把定时器赋值给这个变量
                        fun()//再写入需要执行的函数
                        timer = null//第一次的定时器执行完函数最后会设定变量为false,这里的 timer = null有两个作用,1、开启下一次的入口,2、清除后面的定时器
                    })

                }
            }
        }
function testUname(){
    console.log(Math.random())
}
document.getElementById('myinput').addEventListener('input',debounce(testUname))

一、什么是函数防抖

同样的,节流函数也要解决this和arguments的问题,改进后如下:


//箭头函数写法
function debounce(fun,wait=1000){
            let timer = null
            return function(){
                if(!timer){
                    timer = setTimeout(()=>{
                        fun.apply(this,arguments)
                        timer = null
                    },wait)

                }
            }
}
//参数保存法
function debounce(fun,wait=1000){
        let timer = null
        return function(){
            let _this = this
            let arg = arguments
            if(!timer){
                timer = setTimeout(function(){
                    fun.apply(_this,arg)
                    timer = null
                },wait)

            }
        }
}

3、函数节流的使用场景

到此为止,相信各位应该对函数节流有了一个比较详细的了解,那函数节流一般用在什么情况之下呢?

  • 懒加载、滚动加载、加载更多或监听滚动条位置;
  • 百度搜索框,搜索联想功能;
  • 防止高频点击提交,防止表单重复提交;

总结

到此这篇关于JS防抖节流函数的实现与使用场景的文章就介绍到这了,更多相关JS防抖节流函数内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

作者最新文章