防抖与节流的最佳方案

防抖

函数防抖(debounce): 事件响应函数在一段时间后才执行。如果在这段时间内再次调用,则重新计算执行时间,当预定时间内没有再次执行,该函数则执行相应时间
应用场景:

  1. scroll事件滚动触发
  2. 搜索框
  3. 按钮提交
  4. 浏览器resize事件

函数节流(throttle): 如果持续触发事件,每隔一段事件只执行一次事件
应用场景

  1. dom拖拽
  2. 射击游戏
  3. 鼠标移动
  4. 监听滚动事件

解决:
1.使用underscore.js库
https://underscorejs.net/#
2.手写(仿underscore.js)

防抖实例

let container = document.querySelector("#container")
container.onmousemove = debounce(dosomething, 1000)
function dosomething(e) {
  container.innerHTML = count++
  // this指向container
  console.log(this)
  //如果有返回值
  return '想要的结果'
}
// immediate 立即调用,不等延迟
function debounce(func, wait, immediate) {
  let timer, arg, context
  let result //返回值
  let decounced = function () {
    
    context = this
    args = arguments
    if (timer) clearTimeout(timer)
    if (immediate) {
    // 立即执行
      let callNow = !timer
      timer = setTimeout(() => {
        timer = null
      }, wait)
      // 返回值
      // this指向container
      if (callNow) result = func.apply(this, arg)
    } else {
      // 不会立即执行
      timer = setTimeout(() => {
        func.apply(this, arg)
      }, wait)
    }
    // 返回值
    return result
  }
  // 取消防抖方法
  decounced.cancel = function () {
    clearTimeout(timer)
    timer = null //避免内存泄漏
  }
  return decounced
}
// 取消防抖
let doSome = debounce(dosomething, 1000)
// 取消
btn.onclick = function () {
  doSome.cancel()
}

节流实例
1.使用定时器

function throttle(func, wait) {
  let args, timeout
  let context 
  return function () {
  	context = this
    args = arguments
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null
        // 改变this
        func.apply(context, args)
      }, wait)
    }
  }
}
function dosomething(e) {
  container.innerHTML = count++
}
// 调用
container.onmousemove = throttle(dosomething, 1000)

2.时间戳

function throttle (func, wait) {
  let args
  // 之前的时间戳
  let previos = 0;
  return function () {
    args = arguments
    // 获取当前时间戳
    let now = new Date().valueOf()
    // 当前时间-之前时间大于等待时间,执行
    if (now - previos > wait) {
      // 立即执行
      func.apply(this, args)
      // 之前时间重新赋值
      previos = now
    }
  }
}
function dosomething(e) {
  container.innerHTML = count++
}
// 调用
container.onmousemove = throttle(dosomething, 1000)

3.使用时间戳和定时器优化(手写underscore)

// 时间戳方法 第一次触发,最后一次不触发
// 定时器方法  第一次不触发, 最后触发
// 第一次触发, 最后触发
function throttle1(func, wait) {
  let args, timeout
  let previos = 0
  let later = function () {
    previos = new Date().valueOf()
    timeout = null
    func.apply(this, args)
  }
  return function () {
    args = arguments
     let now = new Date().valueOf()
    if (now - previos > wait) {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null
      }
      // 立即执行
      func.apply(this, args)
      previos = now
    }
    else if (!timeout) {
      timeout = setTimeout(later, wait)
    }
  }
}

// 实现定时器和时间戳优化
// 第三个参数option:{leading: 第一次, trailing: 最后一次}
// {leading: true  第一次触发, trailing: true 最后一次也触发}
// {leading: true  第一次触发, trailing: false 最后一次不触发}
// {leading: false 第一次不触发, trailing: true 最后一次被触发}
// 同时为false 有bug, 同underscore.js
function throttle(func, wait, option) {
  let args, timeout,context
  let previos = 0
  if(!option) option = {}
  let later = function () {
    previos = new Date().valueOf()
    timeout = null
    func.apply(context, args)
  }
  return function () {
    args = arguments
    context = this
     let now = new Date().valueOf()

    if(option.leading === false && !previos) {
      previos = now
    }
    if (now - previos > wait) {
      // 第一次回直接执行
      if (timeout) {
        clearTimeout(timeout)
        timeout = null
      }
      // 立即执行
      func.apply(context, args)
      previos = now
    }
    else if (!timeout && option.trailing !== false) {
      // 最后也会执行
      timeout = setTimeout(later, wait)
    }
  }
}
function dosomething(e) {
  container.innerHTML = count++
  // 改变this指向
  console.log(this)
  return '结果'
}

// let doSome = throttle(dosomething, 10000, {
//   leading: false, //禁止第一次执行
//   trailing: false  //禁止最后异常执行 不能同时为false,第二下进入是第一次不执行
// })

container.onmousemove = throttle2(dosomething, 2000, {
  leading: false,
  trailing: false
})

你可能感兴趣的:(javascript,防抖,节流)