手记

防抖和节流的区别和实现详解(中高级前端面试必备知识)

前言

什么是防抖?什么是节流?它们之间有什么区别?你能举例说明一下吗?

上面这些问题在面试的时候你有被问到过吗?网络上也有很多文章已有说明,但是大部分由于篇幅过长或者描述不清晰,导致难以理解。因此,自己结合了实际的案例和大家分享一下。篇幅很短,花几分钟就可读完,如果有不明白的地方,欢迎在下方留言讨论。

简介

在网页运行的某些场景中,有些事件会不间断的被触发。如scroll事件并不是我们想象中的,滚动一次触发一次。而是会多次被触发,由于过于频繁地DOM操作和资源加载,严重影响了网页性能,甚至会造成浏览器崩溃。

常见的应用场景

  1. 最常见的场景 scroll 事件。
    如下。当我们对窗口增加滚动事件监听,然后每次滚动时,触发监听的回调函数。
function printScroll  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条当前位置:' + scrollTop);
}
window.addEventListener('scroll', printScroll)

但是,在运行时我们发现滚动一下触发多次回调函数,打印结果如下:

然而实际开发中我们并不需要如此高频的回调,毕竟浏览器的性能是有限的,不应该浪费在这里。那么如何优化这种情况了。

防抖(debounce)

含义:事件被触发后延迟n秒再执行回调,如果在这n秒内又被触发,则重新计时。

具体实现:原理就是利用闭包。

// 防抖函数(简洁版)
function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {
        // 每次执行前先清除定时器,以确保在delay时间内fn函数不被执行。
        timer && clearTimeout(timer) 
        timer = setTimeout(fn, delay)
    }
}
// 原始函数
const handlerScroll = function() {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条当前位置:' + scrollTop);
}
// 两函数结合,实现滚动防抖
const scrollHandler = debounce(handlerScroll, 1000)
window.addEventListener('scroll', scrollHandler)

// 注:以上代码可copy到控制台直接测试

此时会发现,必须在停止滚动1秒以后,才会打印出滚动条位置。
注:实际开发中需要通过apply来获取函数的作用域和变量fn.apply(context, args)

实际开发中需要防抖处理的场景还是非常多的,如resize事件scroll事件input事件拖拽事件等。除了这些,还有很多情况需要我们结合实际开发处理。

节流(throttle)

顾名思义就是每过n秒仅执行一次回调函数。如单位时间内多次触发函数,也只有一次生效。

// 节流函数
function throttle(fn, delay) {
    let timer = null;      //定义一个定时器
    return function() {
        let context = this;
        let args = arguments;
        if(!timer) {
            timer = setTimeout(function() {
                fn.apply(context, args);
                timer = null;
            }, delay);
        }
    }
}
// 原始函数
const scrollEvent = function() {
  console.log('当前时间戳:' + new Date().getTime());
}
// 两函数结合,实现节流防抖
const scrollHandler = throttle(scrollEvent, 1000)
// 滚动事件
window.addEventListener('scroll', scrollHandler);

// 注:以上代码可copy到控制台直接测试

连续滚动5s的实际效果:

由于setTimeout函数的时间参数存在误差(或者说执行函数本身所需要的时间),所以打印的结果后三位不一定是我们期望的数值。节流函数除了利用定时器的方式,也可以利用时间戳的方式。当前时间与上一个时间进行比对,这里就不赘述了。

总结

综上所述,防抖是事件停止触发且过了某指定时间后执行一次,而函数节流是间隔某指定的单位时间执行一次。

防抖和节流能有效减少浏览器引擎的损耗,防止出现页面堵塞卡顿现象,作为大前端开发人员是应该熟练掌握的技能。

面试过程中你有被问倒过哪些问题?欢迎在下方留言讨论。如果发现文章中有误的地方欢迎指出。如果觉得有帮助,不妨点赞、关注支持一下,非常感谢!

作者:tager

1人推荐
随时随地看视频
慕课网APP