继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

前端性能优化|什么是防抖和节流?

青云技术社区
关注TA
已关注
手记 36
粉丝 2
获赞 22

防抖与节流、节流与防抖,是不是经常让你不知道谁是谁。

乘电梯,如果有人进入电梯(触发事件),电梯门会等待 5 秒再关闭,在等待期间如果又有人按电梯进入(在 5 秒内再次触发该事件),电梯门又要重新等待 5 秒,直到最后一个人进入电梯,电梯门在等待 5 秒后关闭。

这就是我们生活中遇见的防抖,那节流是什么呢?

打过游戏的朋友都知道,游戏当中技能的使用是有冷却时间的,就算你不停地按技能,也只能在规定时间内触发一次,这就是节流。防抖和节流是前端优化经常遇见的知识点,快拿好小板凳和我一起开启接下来的学习吧!

函数防抖(debounce)

1、原理

当持续触发事件时,在规定的时间内该事件没有被再次调用,事件处理函数就会执行一次,如果在规定时间内事件再次被调用,就重新开始计时。

2、使用场景

按钮提交场景:防止多次提交按钮,只执行最后提交的一次。

搜索框的联想词:只发送最后一次输入结果的请求。

进行窗口的 resize、scroll 事件时: 只计算最后一次结果进行执行。

输入框内容的校验:只进行最后一次输入的内容校验。

function debounce(func, wait, immediate) {
  let timer;
  let debounced = function () {
    let _this = this;
    let args = arguments;
    clearTimeout(timer);
    if (immediate) {
      let executeNow = !timer;
      timer = setTimeout(function () {
        timer = null;
      }, wait);
      if (executeNow) {
        func.apply(_this, args);
      }
    } else {
      timer = setTimeout(function () {
        func.apply(_this, args)
      }, wait);
    }
    debounced.cancel = function () {
      clearTimeout(timer);
      timer = null;
    }
  }
  return debounced;
}

3、实现

用 immediate 参数控制函数是否立即执行。如果函数是立即执行的,就立即调用;如果函数是延迟执行的,就缓存上下文和参数,放到延迟函数中去执行。一旦开始一个定时器,只要定时器还在,每次触发函数都会重新计时。一旦事件不触发了,定时器时间到,执行一次事件函数,定时器重置为 null,就可以再次点击了。

函数节流(throttle)

1、原理

当持续触发事件时,保证在规定的时间内调用一次事件处理函数。如果这个单位时间内触发多次函数,只有一次有效。

2、使用场景

DOM 元素的拖拽功能实现: 一个时间周期去获取一次位置并计算,防止超高频次触发位置变动。
进行窗口的 resize、scorll 事件时: 只计算最后一次结果进行执行。

3、实现

**时间戳方式:**当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳,如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳;如果小于,就不执行。该方式第一次事件立即执行,最后一次事件不执行。

function throttle(func,wait){
  let _this,args;
  let preTime = 0;
  return function(){
    _this = this;
    args = arguments;
    let now = new Date().valueOf();
    if(now-preTime > wait){
      func.apply(_this,args);
      preTime = now;
    }
  }
}

**定时器方式:**当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行完,然后执行函数,清空定时器,这样就可以设置下个定时器。该方式第一次事件不立即执行,最后一次事件执行。

function throttle(func,wait){
  let _this, args, timer;
  return function(){
    _this = this;
    args = arguments;
    if(!timer){
      timer = setTimeout(() => {
        timer = null;
        func.apply(_this,args);
      },wait);
    }
  }
}

**时间戳 + 定时器方式: **用函数参数实现配置项(leading:boolean、trailing:boolean),控制事件第一次是否立即触发和事件最后一次是否触发。

function throttle(func,wait,options){
  let _this, args, timer;
  let preTime = 0;
  if(!options) options = {};
  return function(){
    _this = this;
    args = arguments;
    let now = new Date().valueOf();
    if(options.leading === false && !preTime)  {
      preTime = now;
    }
    if((now - preTime) > wait){
      if(timer){
        clearTimeout(timer);
        timer = null;
      }
      func.apply(_this,args);
      preTime = now;
    } else if(!timer && options.trailing !== false){
      timer = setTimeout(() => {
        preTime = new Date().valueOf;
        timer = null;
        func.apply(_this,args);
      },wait);
    }
  }
}

总结

函数防抖:

将几次操作合并为一次操作进行。原理是维护一个计时器,规定在 delay 时间后触发函数,但是在 delay 时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

函数节流:

使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

两者的区别:

函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。

作者

林茂

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP