防抖与节流


前言

昨天晚上考核开了个会,被师兄师姐问到为啥搜索不写防抖节流,所以今天就给它补上了。

一、防抖和节流是什么?

  • 防抖:就我个人的粗浅理解,防抖就是如果连续多次在规定间隔时间触发同一事件,那么只会执行一次。(它还分有立即执行版本和非立即执行版本)
  • 节流:还是就我个人的粗浅理解,节流就是如果连续多次触发同一事件,那么在你连续触发的时候该事件会以你设定的间隔时间被触发(它有时间戳版本和定时器版本)
  • 我觉得我不能准确用文字描述出来,所以只能尽量在下面配合代码看看能不能说清楚点了。

二、防抖

1.非立即执行版本

代码如下(示例):

  • function debounce(func,wait) {
        let timeout;
        return function() {
            let context = this;
            let args = arguments;
            clearTimeout(timeout);
            timeout = setTimeout(function() {
                func.apply(context,args)
            },wait)
        }
    }
    
    
  • 下面是粗浅的解释:
  • 非立即执行就是在连续触发中不会执行,直到最后一次触发等待wait时间后才会执行函数
  • 进入函数首先声明一个timeout(为下方的定时器)
  • 此次是高阶函数,返回了一个函数function,在function里面用context接收this,用args接收arguments(因为不知道函数参数的个数,所以需要这个)
  • 如果不用context接收this,直接在下面定时器func.apply(this,args)的话,那么这个this指向的是window,而不是func的this
  • 每次触发进入function,就清空一次定时器,让其无法执行,直到最后一次触发,等待wait时间后,才会执行func.apply(context,args)调用传入的函数

2.立即执行版本

代码如下(示例):

function debounce(func,wait) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        // 第一次进入时,timeout为undefined,!timeout为真,直接触发
        if(!timeout) {
            func.apply(context,args)
        }
         // 之后进入时,如果timeout存在,就把它设为null,让他无法执行func
        if(timeout) {
            clearTimeout(timeout)
        }
        // 每次进入重新设置timeout,刷新wait,直到最后一次等待wait后执行func
        timeout = setTimeout(() => {
            func.apply(context,args)
        },wait)
    }
}

  • 下方是粗浅的解释:
  • 立即执行版本就是在触发的时候会立即执行一次函数,然后在最后等待wait时间后才会再次触发
  • 这里的context和args同上
  • 第一次进入时,由于timeout是undefined,所以!timeout为真,立即执行了一次函数
  • 之后进入时,如果timeout存在,就把它设为null,让他无法执行func
  • 每次进入重新设置timeout,刷新wait,直到最后一次等待wait后执行func

3.二合一版本

function debounce(func,wait,immediate) {
    let timeout;
    return function() {
        let context = this;
        let args = arguments;
        clearTimeout(timeout);
        // 立即执行
        if(immediate) {
            // 第一次进入的时候tiomeout为undefined,此时callNow为真
            let callNow = !timeout;
            //如果在wait内再次触发,则timeout还没等于null,也就是callNow为假,不会执行函数
            //直到某次超过wait了,那么timeout等于null,callNow为真,最后会执行一次
            timeout = setTimeout(() => {
                timeout = null;
            },wait)
            if(callNow) { //第一次进入的时候callNow为真,立即执行一次
                func.apply(context,args)
            }
        } else {
            // 不会立即执行
            timeout = setTimeout(function() {
                func.apply(context,args)
            },wait)
        }
    }
}
  • 下方是粗浅的解释:
  • 啊解释都在注释里了我就不再复制一遍了吧
  • 主要区别就是多了一个immediate,当它为true时,会立即执行,不为true时,不会立即执行
  • 使用方法:
    debounce(func,200,true)


三、节流

1.时间戳版本

function throttle(func,wait) {
    let context,args;
    // 之前的时间戳
    let previous = 0;
    return  function() {
        context = this;
        args = arguments;
        // 获取当前的时间戳
        let now = new Date().valueOf()
        if(now - previous > wait) {  // 因为第一次的now很大,所以会立即触发
            // 立即执行
            func.apply(context,args)
            previous = now;
        }
    }
}
  • 在首次进入时,声明一个前时间戳previous为0
  • 在return 的function里面,获取当前的时间戳now
  • 因为第一次获取的now很大,所以第一次的now-previous一定大于wait(除非你的wait设置了很多年),会立即执行func,在执行完毕后让previous=now(把执行时刻的时间戳赋给前时间戳)
  • 在后方不断触发的时候会不断重新获取现有时间戳,以wait为间隔执行func

2.定时器版本

function _throttle(func,wait) {
    let context,args,timeout;
    return function() {
        context = this;
        args = arguments;
        if (!timeout) {
            timeout = setTimeout(() => { // 当第一次进入的时候,会在wait到点后触发,然后timeout为null,能再次进入,如果没到wait时间,timeout有值,就进不去
                func.apply(context,args)
                timeout = null;
            },wait)
        }
    }
}
  • 在第一次进入的时候,timeout为undefined。!timeout为真,进入if为timeout设置执行内容
  • 如果在还没到wait时间内再次触发,此时timeout是有值的,不会进入if,也就不会重置timeout
  • 等到wait后执行timeout内的语句,执行了func,并把timeout设为null,使执行后再次触发可以重新给timeout设置执行内容


总结

  • 本人水平仍不足,解释可能解释得很乱,不能把想要表达的东西清晰地表达出来
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值