优化 防抖 节流

134 阅读2分钟

防抖

  • 持续触发事件时。一定时间没有继续触发,事件处理函数才会执行一次

  • input (巨量引擎)

如果有人进电梯,那电梯将在10秒钟后出发,这时如果又有人进电梯了,我们又得等10秒再出发

  • 通过闭包维护一个变量,此变量代表是否已经开始计时,如果已经开始计时则清空之前的计时器,重新开始计时

场景

  1. 表单提交:当用户停止输入一段时间后才会发送请求

  2. 搜索框自动补全:当用户在搜索框中输入关键词时,实时查询后台数据并展示自动补全列表

  3. 窗口大小改变:当窗口大小改变时,需要重新计算页面布局

实现

function debounce(fn, time) {
  let timer = null
  return function () {
    let context = this
    let args = arguments
    if (timer) {
      clearTimeout(timer)
      timer = null
    }
    timer = setTimeout(function () {
      fn.apply(context, args)
    }, time)
  }
}

window.onscroll = debounce(function () {
  console.log('触发' + new Date().getTime())
}, 1000)

节流

  • 持续触发事件时,保证一定时间段内只调用一次事件处理函数
  • 游戏内的技能冷却,无论你按多少次,技能只能在冷却好了之后才能再次触发

  • 通过闭包维护一个变量,此变量代表是否允许执行函数,如果允许则执行函数并且把该变量修改为不允许,并使用定时器在规定时间后恢复该变量

场景

  1. 页面滚动

    • resize scroll
  2. 频繁点击按钮:确保只有在一定时间内才能触发一次事件

  3. 实时网络传输:控制发送数据的频率

实现

// 节流
// 时间戳写法
// 第一次执行时 last 为 0 ,所以是立即执行
function throttle(fn, interval) {
  let last = 0
  return function () {
    let now = Date.now()

    if (now - last >= interval) {
      last = now
      fn.apply(this, arguments)
    }
  }
}

function handle() {
  console.log(Math.random())
}

const throttleHandle = throttle(handle, 1000)

throttleHandle()

// 第一次不立即执行,但是最后一次会有延迟

function throttle2(fn, interval) {
  let timer = null
  return function () {
    let context = this
    let args = arguments

    if (!timer) {
      timer = setTimeout(() => {
        fn.apply(context, args)
      }, interval)
    }
  }
}

// 结合版本
function throttle3(fn, delay) {
  let timer = null
  let startTime = Date.now()

  return function () {
    let curTime = Date.now()
    let remainning = delay - (curTime - startTime)
    let context = this
    let args = arguments
    clearTimeout(timer)
    if (remainning <= 0) {
      fn.apply(context, args)
      startTime = Date.now()
    } else {
      timer = setTimeout(fn, remainning)
    }
  }
}

image.png