节流throttle和throttle函数

4,571 阅读4分钟

前言

个人对节流木得啥感觉,所以想对节流函数进行复盘,总结一下。

正文

我们先来看看什么是节流?为什么要节流?有啥作用?具体咋写?

什么是节流?

在事件被触发后,在规定时间内无论在怎么触发只会调用一次函数,直到时间结束

个人理解就是游戏人物的霸体,霸体期间我们怎么打他,他都不会倒下,只能等时间结束霸体效果消失

为什么要节流?有啥作用?

优化项目的性能,让项目运行的更快更好。
减少一些时间的频繁调用,例如scroll(懒加载要记录滚动条的位置)、mousemove(鼠标移动)等等

还有一个重要作用就是面试可能会问,我们必须知道。

具体咋写?

定时器版

第一个参数是我们要执行的函数
第二个就是时间
function throttle(func,delay){
  let timer = null
  retrun function(...args){
    // let args=arguments 也可以写成这种或...args也是代表我们传过来的实参
    if(!timer){
      timer=setTimeOut(()=>{
         func.apply(this,args)
         timer=null
      },dealy)    
    }
    // 当我们第一次触发事件,定时器不存在时就执行函数,当我们再次点击时,因为定时器存在,
    // 所以无法再进入函数调用(无论事件如何执行),那么只能等定时器事件结束,
    // 我们让timer=null,回到第一次的状态,就又重新开始新的一轮
  }
}

这种功能性的函数,其实会用到很多地方,我们可以额外将其封装成一个js文件,
通过export function将其导出,再到具体使用文件里导入然后调用函数

时间戳版

function throttle(func,delay){
   let start=0
   //let start=+new Date() 不可以这样写,会导致无法第一次就执行函数
   return function(...args){
     let now=+new Date() //通过+号可以转化成时间戳
     if(now-start>delay){
       func.apply(this,args)
       start=now
     }
   }
   //第一次会立即触发事件调用函数,通过判断前后触发事件的时间间隔是否大于设置的等待时间
   //大于就证明已经过了规定时间,可以再次调用函数,否则反之
}

时间戳版和定时器版区别

二者区别在于时间戳版会立即执行,好像也是存在的原因(没去了解),而定时器版是最后一次会立即执行。

但其实定时器版也可以第一次立即执行。其实只要稍作修改即可实现。

function throttle(func, delay) {
    let timer = null
    return function (...args) {
      if (!timer) { 
        func.apply(this, args)//先执行函数
        timer = setTimeout(() => {
          timer = null;
        }, delay)
      }
    }
  }

咋用呢?

这里结合小案例来说,以下是定时器版

没有使用节流throttle函数的情况

<div id="box"></div>
let box = document.getElementById('box')
let count = 1;
function doSomething() {
  box.innerHTML = count++;
  console.log('1')
};
box.onmousemove = doSomething
当我们讲鼠标在box里一直移动,他的数字会疯狂增加,会一直打印1

效果图

image.png

使用节流throttle函数的情况

let box = document.getElementById('box')
let count = 1;
function doSomething() {
    box.innerHTML = count++;
    console.log('1')

};
// box.onmousemove = doSomething
box.onmousemove = throttle(doSomething, 2000);

结果如下,打印的次数减少了,建议上机体验(在外面写的博客,没工具啊,不然就换成gif了)

image.png

额外

听说如果面试官比较BT的话,会让你写第一次也执行,中间还是节流,最后一次也要执行。这种时候不能说不会,而是我们无敌装B高光时刻就到了,将定时器和时间戳合并,俗称节流合体双修版。嘿嘿嘿嘿!

节流合体双修版

function throttle(func, delay) {
  let start=0
  let timer=null
  return function (...args) {
    let now = +new Date();
    if (now - start < delay) {
       if (timer) clearTimeout(timer)
       // timer && clearTimeout(timer)//两种都行
       //  && 先算 && 左侧,若左侧为 false 那么右侧就不运算了。
        timer = setTimeout(() => {
            start = now;
            func.apply(this, args);
        }, delay);
       } else {
         start = now;
         func.apply(this, args);
      }
   }
}

总结

节流函数是指在一定时间范围内减少事件的触发频率

时间戳版和定时器版的区别在于时间戳版会立即执行,而定时器版是最后一次会立即执行,但是定时器也可以第一次执行

结合应用场景

1.搜索框联想,用户在输入值的时候,个人认为用函数节流也可以来减少请求数据的次数,不过更多用的是防抖。

2.在页面的加载场景,用户在滚动页面时,可以每隔一段时间发一次 Ajax 请求

3.等等等等。。。。。。

如果你有兴趣可以再去看看我写的debounce防抖

防抖debounce && 防抖函数的作用

拓展

SegmentFault:函数节流与函数防抖

掘金:函数节流与函数防抖

alloween:防抖、节流