节流 throttle

120 阅读2分钟

防抖 (debounce) :多次触发,只在最后一次触发时,执行目标函数。

节流(throttle)技能冷却中:限制目标函数调用的频率,比如:1s内不能调用2次。

举例子

假设调用闪现,d就是fn,是一个函数

const d = () =>{
consolo.log('闪现')
}

let 冷却中 = false
let timer = null

function sx() {
if(冷却中){return}
d()
冷却中 = true
timer = seTimeout(()=>{
冷却中 = false
},120*1000)
}

解释:

  • d()是一个函数,当调用d()函数时,就会打印闪现;
  • 如果调用d(),就设置一个计时器,刚开始设置timer=null;
  • 设置一个120s的时间,timer = setTimerout(()=>{},120*1000);
  • 120s之后,把冷却中置换一,先设置let冷却中 = false
  • 只要调用d(),就把let 冷却中 = true,120s之后,就把let 冷却中 = false
  • 调用d()之前,先检查一下,if(冷却中){return},就什么也不做。
  • 因为刚开始let 冷却中 = false,所以可以调用d();
  • 可以调用d()之后,冷却中 = true,要等120s后,才可以变成false,函数运行;
const createFn = (f,time) = >{

return ()=>{

  }
}

综合一下

const d = () =>{
console.log('闪现')
}

const createFn = (f,time) => {
let 冷却中 = false
let timer = null

return (...args)=>{

if(冷却中){return}
f(...args)
冷却中 = true
timer = setTimeout(()=>{
冷却中 = false
},time)
  }
}

const d2  = createFn(d,120*1000)

正常版本

const d = () =>{
console.log('闪现')
}

const throttle = (f,time) => {
let flag = false
let timer = null

return (...args)=>{

if(flag){return}
f(...args)
flag = true
timer = setTimeout(()=>{
flag = false
},time)
  }
}

const d2  = throttle(d,120*1000)

使用场景

比如绑定响应鼠标移动、窗口大小调整、滚屏等事件时,绑定的函数触发的频率会很频繁。若稍处理函数微复杂,需要较多的运算执行时间和资源,往往会出现延迟,甚至导致假死或者卡顿感。为了优化性能,这时就很有必要使用 debounce 或 throttle 了。

// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {
  // 上一次执行 fn 的时间
  let previous = 0
  // 将 throttle 处理结果当作函数返回
  return function(...args) {
    // 获取当前时间,转换成时间戳,单位毫秒
    let now = +new Date()
    // 将当前时间和上一次执行函数的时间进行对比
    // 大于等待时间就把 previous 设置为当前时间并执行函数 fn
    if (now - previous > wait) {
      previous = now
      fn.apply(this, args)
    }
  }
}

// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)
// 节流就是「技能冷却中」
const throttle = (fn, time) => {
let 冷却中 = false return (...args) => { 
if(冷却中) return fn.call(undefined, ...args) 冷却中 = true setTimeout(()=>{ 冷却中 = false }, time) } } 
// 还有一个版本是 在冷却结束时调用 fn 
// 简洁版,删掉冷却中变量,直接使用 timer 代替
const throttle = (f, time) => { 
let timer = null return (...args) => {
if(timer) {return} f.call(undefined, ...args) timer = setTimeout(()=>{ timer = null }, time) } }