JavaScript 函数防抖(debounce)的实现

20 篇文章 1 订阅
20 篇文章 1 订阅

函数防抖是什么

函数防抖是指对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时,是常见的优化,适用于

  • 表单组件输入内容验证
  • 防止多次点击导致表单多次提交

等情况,防止函数过于频繁的不必要的调用。

代码实现

思路

setTimeout 实现计时,配合 clearTimeout 实现“重新开始计时”。

即只要触发,就会清除上一个计时器,又注册新的一个计时器。直到停止触发 wait 时间后,才会执行回调函数。

不断触发事件,就会不断重复这个过程,达到防止目标函数过于频繁的调用的目的。

初步实现

function debounce(func, wait) {
    let timeout
    return function () {
        clearTimeout(timeout)
        timeout = setTimeout(func, wait) //返回计时器 ID
    }
}

示意

container.onmousemove = debounce(doSomething, 1000);

注解:关于闭包

每当事件被触发,执行的都是那个被返回的闭包函数。

因为闭包带来的其作用域链中引用的上层函数变量声明周期延长的效果,debounce 函数的 settimeout计时器 ID timeout 变量可以在debounce 函数执行结束后依然留存在内存中,供闭包使用。

优化:修复

相比于未防抖时的

container.onmousemove = doSomething 

防抖优化后,指向 HTMLDivElement 的从 doSomething 函数的 this 变成了闭包匿名函数的 this ,前者变成了指向全局变量。
同理,doSomething 函数参数也接收不到 MouseEvent 事件了。

修复代码

function debounce(func, wait) {
    let timeout
    return function () {
        let context = this //传给目标函数
        clearTimeout(timeout)
        timeout = setTimeout(
            ()=>{func.apply(context, arguments)} //修复
        , wait)
    }
}

优化:立即执行

相比于 一个周期内最后一次触发后,等待一定时间再执行目标函数;

我们有时候希望能实现 在一个周期内第一次触发,就立即执行一次,然后一定时间段内都不能再执行目标函数。

这样,在限制函数频繁执行的同时,可以减少用户等待反馈的时间,提升用户体验。

代码

在原来基础上,添加一个是否立即执行的功能

function debounce(func, wait, immediate) {
    let time
    let debounced = function() {
        let context = this
        if(time) clearTimeout(time)

        if(immediate) {
            let callNow = !time
            if(callNow) func.apply(context, arguments)
            time = setTimeout(
                ()=>{time = null} //见注解
            , wait)
        } else {
            time = setTimeout(
                ()=>{func.apply(context, arguments)}
            , wait) 
        }
    }
    return debounced
}

注解

把保存计时器 ID 的 time 值设置为 null 有两个作用:

  • 作为开关变量,表明一个周期结束。使得 callNowtrue,目标函数可以在新的周期里被触发时被执行
  • timeout 作为闭包引用的上层函数的变量,是不会自动回收的。手动将其设置为 null ,让它脱离执行环境,一边垃圾收集器下次运行是将其回收。

优化:取消立即执行

添加一个取消立即执行的功能。

函数也是对象,也可以为其添加属性。

为了添加 “取消立即执行”功能,为 debounced 函数添加了个 cancel 属性,属性值是一个函数

debounced.cancel = function() {
        clearTimeout(time)
        time = null
 }

示意:

var setSomething = debounce(doSomething, 1000, true)

container.onmousemove = setSomething

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

完整代码

function debounce(func, wait, immediate) {
    let time
    let debounced = function() {
        let context = this
        if(time) clearTimeout(time)

        if(immediate) {
            let callNow = !time
            if(callNow) func.apply(context, arguments)
            time = setTimeout(
                ()=>{time = null} //见注解
            , wait)
        } else {
            time = setTimeout(
                ()=>{func.apply(context, arguments)}
            , wait) 
        }
    }

    debounced.cancel = function() {
        clearTimeout(time)
        time = null
    }

    return debounced
}

参考:https://github.com/mqyqingfeng/Blog/issues/22#issuecomment-357874221

  • 12
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JavaScript 函数防抖debounce)是一种技术,可以防止函数在短时间内多次触发。 当函数被触发时,防抖函数会延迟执行函数,并且如果在延迟期间内再次触发函数,则会重新计算延迟时间。这样可以避免函数在短时间内多次触发,从而节省资源。 举个例子,假设你有一个函数,用于搜索用户输入的内容。如果每次用户输入都立即触发函数,会导致函数频繁触发,浪费资源。使用防抖函数,可以在用户输入后延迟一段时间才触发函数,从而节省资源。 下面是一个简单的防抖函数的例子: ``` function debounce(fn, delay) { let timer = null; return function () { const context = this; const args = arguments; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); } } ``` 上面的防抖函数接受两个参数:`fn` 是要进行防抖函数,`delay` 是延迟时间(单位为毫秒)。防抖函数返回一个新函数,在新函数中设置了延迟执行的逻辑。 使用防抖函数的方法如下: ``` const debouncedFunction = debounce(function () { // 在这里 ### 回答2: JavaScript 函数防抖是一种常用的优化技术,旨在减少函数的调用频率。 当一个函数被频繁触发时,防抖机制会在一定的延迟时间内,只执行最后一次触发的函数调用。这样可以避免函数被频繁执行,提高性能和用户体验。 实现函数防抖有两种方式:立即执行和延迟执行。 立即执行的函数防抖,意味着只有当函数被最后一次调用时,才会立即执行函数。延迟执行的函数防抖,意味着只有当函数在一定时间内没有被再次调用时,才会执行函数。 通过使用定时器和闭包,可以实现函数防抖的功能。当函数被触发时,先清除之前设置的定时器,然后重新设置一个延迟执行的定时器。如果在延迟时间内再次触发函数,就会清除之前设置的定时器,重新设置一个新的延迟执行的定时器。只有当延迟时间内没有再次触发函数,定时器才会执行函数函数防抖在多种场景中都有应用。比如在用户输入搜索框时,可以使用函数防抖来减少发送搜索请求的频率;在窗口大小改变时,可以使用函数防抖来优化页面重绘的性能。 总之,JavaScript 函数防抖是一种常用的优化技术,通过减少函数的调用频率来提高性能和用户体验。在实现上,可以通过定时器和闭包来实现函数防抖的功能。 ### 回答3: JavaScript函数防抖是一种提高性能和优化用户体验的技术。它所解决的问题是在一段时间内频繁触发某个函数时,只执行最后一次触发的函数调用。 实现函数防抖的方法是利用定时器。当触发事件时,会开始一个定时器,如果在指定的时间间隔内再次触发了该事件,定时器就会被清除并重新开始计时。这样,只有在最后一次触发事件后的等待时间内没有再次触发,才会执行相应的函数调用。 函数防抖在实际应用中有很多场景。比如,在用户输入搜索框时,可以利用函数防抖来减少发送请求的次数,只在用户停止输入一段时间后才发起实际的搜索请求。又如,在窗口大小调整时,可以利用函数防抖来优化响应式布局,只在窗口停止调整一段时间后才重新计算样式。 以下是一个简单的实现函数防抖的示例代码: ```javascript function debounce(func, delay) { let timerId; return function() { const context = this; const args = arguments; clearTimeout(timerId); timerId = setTimeout(function() { func.apply(context, args); }, delay); }; } // 创建一个防抖函数 const debouncedFunc = debounce(function() { console.log('Function debounced'); }, 300); // 触发函数 debouncedFunc(); // 不会执行 debouncedFunc(); // 不会执行 debouncedFunc(); // 不会执行 // 等待300毫秒后,只执行一次 ``` 以上示例代码中,`debounce`函数接受一个函数和一个延迟时间参数,返回一个新函数实现函数防抖的逻辑。在创建防抖函数后,多次调用这个函数,只有停止调用一段时间后才会执行实际的函数逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值