节流与防抖,以及自身体会

465 阅读3分钟

节流与防抖,以及自身体会

节流

在前端页面中存在着很多高频事件,如:浏览器的滚动事件,输入框实时校验等。如果不做处理,一定程度上会影响性能。

节流:函数执行之后,在规定的时间内不再触发。其实现思路如下:

  • 记录上一次函数执行完毕的时间,初始化为0
  • 记录本次开始执行函数前的时间
  • 这两次时间相减,如果大于规定的时间就执行,反之不执行
function throttle(fn, delay) {
    // 上一次执行函数执行完的时间
    var lasttime = 0
    // 当前这次开始i 执行函数前的时间
    var now = Date.now()
    if(now - lasttime > delay) {
        fn()
        lasttime = Date.now()
    }
 }
 
 document.body.onscroll = function() {
    throttle(function(){console.log('scroll')}, 300) 
 }

按照上诉思路写下来会出现一个问题

  • 每次滚动都会初始化lasttime。(所以需要保存变量lasttime)
function throttle(fn, delay) {
    // 上一次执行函数执行完的时间
    var lasttime = 0
    return function() {
        // 当前这次开始i 执行函数前的时间
        var now = Date.now()
        if(now - lasttime > delay) {
            fn()
            // 重置时间
            lasttime = Date.now()
        }
    }
 }

 // 绑定一个滚动触发的事件

 document.body.onscroll = throttle(function() {
    console.log('scroll-->', Date.now())
 }, 300)
  • 使用闭包保存上一次执行完毕的时间
  • 运行结果可以发现,相邻两次输出的时间指差大于300

防抖

防抖:一个需要高高频触发的函数,在规定的时间内,只让最后一次生效,前面的不生效

这个功能通常用于防止用户猛烈点击表单提交按钮。

知道定义之后,大概的实现思路:

  • 使用定时器
  • 保存上一次的定时器对象
  • 不停的清除上一次定时器对象,只保留最后一次的定时器对象
function debounce(fn, delay){
    var timer = null
    return function() {
        // 不停的清除定时器 保留最后一次的定时器 
        //  清楚上一次的timer
        clearTimeout(timer)
        timer = setTimeout(function() {
            fn()
        }, delay)
    }
  }

  document.getElementById('btn').addEventListener('click', debounce(function(){
    console.log('click')
  }, 300))

以上也使用了闭包来保存了上一次的定时器对象。

对于delay的设定需要谨慎。如果我们上一次点击按钮与当前只一次点击按钮的时间之差小于delay,那么上一次的定时器就会被清除,重新启动一次定时器。在delay的延迟之后执行函数。所以如果delay的数值如果设置过长,延迟就越长。

节流与防抖的区别

假如我们都用节流与防抖来做输入框的实时校验。

对于节流来说:

  • 输入框第一次输入的时候就回去校验。
  • 然后然后在规定时间内不再去触发。
  • 如果最后一次与倒数第二次的时间间隔小于delay,最后一次不等去校验。
  • 从上面可以看得出来,用节流做输入框校验有一定的风险

对于防抖:

  • 开始输入的时候不会马上校验
  • 最后一次输入完始终回去校验
  • 始终会有delay的延迟。

综上所诉两者有好处也同时存在风险,具体场景做合理的选择。