防抖和节流简介

背景:近期经常被问到防抖和节流,之前项目中也有遇到并且解决过,猛地一问这么专业的术语如果之前没有听过还真容易发蒙,因此简单整理一下,希望对需要的小伙伴们有所帮助。

可能需要做防抖和节流的场景简单整理如下:

1.判断回到顶部按钮的显示时机,一般需求是当页面滑动距离顶部一定距离之后才需要显示,此时我们一般只需要监听浏览器滚动事件,返回当前滚动条与顶部的距离。代码如下:

function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll  = showTop

但是,实际运行会发现一个问题,这个函数执行频率特别高,这样比较浪费性能,为了优化我们一般会用到防抖来处理。

2.搜索框input事件,例如要支持输入实时搜索可以使用节流方案(间隔一段时间就必须查询相关内容),或者实现输入间隔大于某个值(如500ms),就当做用户输入完成,然后开始搜索,具体使用哪种方案要看业务需求。

3.页面resize事件,常见于需要做页面适配的时候。需要根据最终呈现的页面情况进行dom渲染(这种情形一般是使用防抖,因为只需要判断最后一次的变化情况)。

防抖(debounce)

针对第一种场景,我们可以这么思考:在第一次触发事件时,不立即执行函数,而是给出一个期限值eg:1000ms,然后:

a.如果在1000ms内没有再次触发滚动事件,那么就执行函数;

b.如果在1000ms内再次触发了滚动事件,那么当前的计时器清零,重新开始计时。

结果:如果在我们设置的期限值内大量触发同一事件,只会执行一次函数。

实现:我们使用setTimeOut来实现计时,由于需要用到变量,为了避免全部变量带来污染,使用闭包来实现,代码如下:


function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {
        if(timer){
            clearTimeout(timer) 
        }
        timer = setTimeout(fn,delay) // 简化写法
    }
}
// 然后是监听滚动位置的函数
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop,1000) // 为了方便观察效果我们取个大点的间断值,实际使用根据需要来配置

以上代码实现了防抖功能,也就是滚动条停止滚动1秒以上,才会执行函数,打印出滚动条距离顶部的数值。

防抖定义整理:对于短时间内连续触发的事件(滚动监听),防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。

以上处理方法,也可能会遇到一些问题,比如如果一直按住鼠标一直滚动,这样的话就不会输出我们想要的距离顶部的值,那这个应该怎么解决呢?下面简单说下节流(throttle)。

节流(throttle)

解决上面问题的方法的思路是,即使一直不断触发滚动条,我们也能在某个时间间隔后输出间距值,这时候我们可以设计一个类似开关的定期开放的函数,意思是我们让一个函数执行一次后,在某个时间段内暂时无效,过了这段时间再重新生效,具体代码如下:

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //冷却时间,暂不执行
           return false 
       }
       // 可用时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* 请注意,节流函数还可以有以下思路实现
   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活
*/

// 监听滚动条的滚动函数
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000) 

以上代码解决了防抖带来的问题,如果一直拖着滚动条,也会以1s的时间间隔,持续输出当前位置距离顶部的距离。

希望大家看完能对防抖和节流有所理解,并且在之后的项目中做出相应的处理,如有错误,欢迎指正。

你可能感兴趣的:(js)