JavaScript的节流和防抖

JavaScript4年前 (2020)更新 小马大哥哥
755 0 0

今天一个同学面试被问到一个问题, 谈谈js的函数节流函数防抖

懵逼,一脸的懵逼,这可触碰到我的知识盲区了,好像听也没听过这2个东西,痛定思痛,赶紧学习学习。

函数节流: 规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。

函数防抖: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

应用场景:

函数节流:当给document加scroll事件时,假定处理函数为fn,那么当滑动鼠标时scroll事件会不断的被触发,影响滑动性能,这时可以用节流处理一下 throttle(fn,time),可以保证fn在time时间内只触发一次

函数防抖:当做随着输入框输入不同内容展示不同的结果列表类似需求时,一般会绑定input的change事件,该事件在用户输入过程中会多次被触发,这时可以用防抖处理一下 debounce(fn,time),可以保证在用户输入完time时间后才触发fn。这里不用 throttle,因为debounce更加符合

例子:

  • 节流:实现函数节流我们主要有两种方法:时间戳和定时器

// 时间戳实现方法:
var throttle = function(func, delay) {
    var prev = Date.now();
    return function() {
        var context = this;   //this指向window
        var args = arguments;
        var now = Date.now();
        if (now - prev >= delay) {
            func.apply(context, args);
            prev = Date.now();
        }
    }
}
function handle() {
    console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

这个节流函数利用时间戳让第一次滚动事件执行一次回调函数,此后每隔1000ms执行一次,在*小于1000ms这段时间内的滚动是不执行的

// 定时器实现方法
var throttle = function(func, delay) {
    var timer = null;
    return function() {
        var context = this;
        var args = arguments;
        if (!timer) {
            timer = setTimeout(function() {
                func.apply(context, args);
                timer = null;
            }, delay);
        }
    }
}
function handle() {
    console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

当触发事件的时候,我们设置了一个定时器,在没到1000ms之前这个定时器为null,而到了规定时间执行这个函数并再次把定时器清除。也就是说当第一次触发事件,到达规定时间再执行这个函数,执行之后马上清除定时器,开始新的循环,那么我们看到的效果就是,滚动之后没有马上打印,而是等待1000ms打印,有一个延迟的效果,并且这段时间滚动事件不会执行函数。

单用时间戳或者定时器都有缺陷,我们更希望第一次触发马上执行函数,最后一次触发也可以执行一次事件处理函数

var throttle = function(func, delay) {
     var timer = null;
     var startTime = Date.now();  //设置开始时间
     return function() {
             var curTime = Date.now();
             var remaining = delay - (curTime - startTime);  //剩余时间
             var context = this;
             var args = arguments;
             clearTimeout(timer);
              if (remaining <= 0) {      // 第一次触发立即执行
                    func.apply(context, args);
                    startTime = Date.now();
              } else {
                    timer = setTimeout(func, remaining);   //取消当前计数器并计算新的remaining
              }
      }
}
function handle() {
      console.log(Math.random());
}
window.addEventListener('scroll', throttle(handle, 1000));

JavaScript的节流和防抖

在节流函数内部使用开始时间startTime、当前时间curTime和剩余时间remaining,当剩余时间小于等于0意味着执行处理函数,这样保证第一次就能立即执行函数并且每隔delay时间执行一次;如果还没到时间,就会在remaining之后触发,保证最后一次触发事件也能执行函数,如果在remaining时间内又触发了滚动事件,那么会取消当前的计数器并计算出新的remaing时间。通过时间戳和定时器的方法,我们实现了第一次立即执行,最后一次也执行,规定时间间隔执行的效果,可以灵活运用在开发中

  • 防抖:

function debounce(fn, wait) {
    var timeout = null;      //定义一个定时器
    return function() {
        if(timeout !== null) {
            clearTimeout(timeout);  //清除这个定时器
         }
        timeout = setTimeout(fn, wait);  
    }
}
// 处理函数
function handle() {
    console.log(Math.random()); 
}
// 滚动事件
window.addEventListener('scroll', debounce(handle, 1000));
  • vue中防抖函数的定义和使用方式
    /**
     * 防抖函数
     * @param fn
     * @param wait
     * @returns {function(...[*]=)}
     */
    debounce(fn, wait) {
      let _this = this;
      return function(...args) {
        if(_this.timeout !== null) clearTimeout(_this.timeout);  //清除这个定时器
        _this.timeout = setTimeout(() => {
          fn.apply(_this, args)
        }, wait);
      }
    }
  // vue中调用防抖函数
    /**
     * 滑块值改变事件
     * @param val
     */
    progressValChange(val) {
      // 调用防抖函数
      this.debounce(function(time) {
        // 播放历史数据
        this.historyPlayer(this.historyData,this.speed,time);
      },500)(val);
    },

JavaScript的节流和防抖

如上所见,当持续触发scroll函数,handle函数只会在1秒时间内执行一次,在滚动过程中并没有持续执行,有效减少了性能的损耗

PS:防抖和节流能有效减少浏览器引擎的损耗,防止出现页面堵塞卡顿现象,应该熟练掌握。最后再次感谢原作者的总结,热心分享技术让我们的生活变得更好

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...