JS防抖和节流

JS防抖和节流

防抖

原理

事件响应函数在一段时间后才执行,如果在这段时间内再次调用,则重新计算执行时间;当预定的时间内没有再次调用该函数,则执行响应逻辑

underscore中的debounce函数可以防抖

应用场景

  1. scroll事件滚动触发的时候
  2. 搜索框输入查询的时候
  3. 表单验证
  4. 按钮的提交事件
  5. 浏览器的窗口缩放,resize事件

自定义防抖函数

/**
 * 防抖函数的自定义实现
 * @param func 执行的函数
 * @param wait 等待的时间
 * @param immediate 是否立即执行
 */
function debounce (func, wait, immediate) {
  // result -- 返回值
  let timeout, result;
  let debounced = function () {
    let self = this
    let args = arguments
    clearTimeout(timeout)
    if (immediate) {
      // callNow是立即执行的变量
      let callNow = !timeout
      timeout = setTimeout(() => {
        timeout = null
      }, wait)
      // 由于最开始timeout为undefined,取反为true,故立即执行
      if (callNow) result = func.apply(self, args)
    } else {
      // 不会立即执行
      timeout = setTimeout(function() {
        //解决执行函数内部this指向问题以及event指向问题
        result = func.apply(self, args)
      }, wait)
    }
    return result
  }
  // 取消
  debounced.cancel = function () {
    clearTimeout(timeout)
    timeout = null // 防止内存泄露
  }
  return debounced
}

节流

原理

如果你持续的触发事件,每隔一段时间,只执行一次事件

应用场景

  1. DOM元素的拖拽功能的实现
  2. 计算鼠标移动的距离
  3. 监听scroll滚动事件

初步实现

/**
 * 节流函数 -- 初步实现 -- 第一次会触发,最后一次不会触发
 * @param func 执行的函数
 * @param wait 等待的时间
 */
function trottle (func, wait) {
  let context, args
  // 之前的时间戳
  let old = 0 // 默认为0
  return function () {
    context = this
    args = arguments
    // 获取当前的时间戳
    let now = new Date().valueOf()
    if (now-old > wait) {
      // 立即执行
      func.apply(context, args)
      old = now
    }
  }
}

改进版本

/**
 * 节流函数 -- 第一次不会触发,最后一次会触发
 */
function trottle (func, wait) {
  let context, args, timeout
  return function () {
    context = this
    args = arguments
    if (!timeout) {
      timeout = setTimeout(() => {
        timeout = null
        func.apply(context, args)
      }, wait)
    }
  }
}

再次改进版本

/**
 * 节流函数
 * 第一次会触发,最后一次会触发
 */
function trottle (func, wait) {
  let context, args, timeout
  let old = 0 // 时间戳
  let later = function () {
    old = new Date().valueOf()
    timeout = null
    func.apply(context, args)
  }
  return function () {
    context = this
    args = arguments
    let now = new Date().valueOf()
    if (now - old > wait) {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null 
      }
      func.apply(context, args)
      old = now
    }

    if (!timeout) {
      timeout = setTimeout(later, wait)
    }
  }
}

最终版本

/**
 * 节流函数
 * 最终版本
 * 第一次不会触发,最后一次会调用 leading:false, trailing:true
 * 第一次会触发,最后一次不会触发 leading:true, trailing:false
 */
function trottle (func, wait, options) {
  let context, args, timeout, result
  let old = 0 // 时间戳
  if (!options) options = {} 
  let later = function () {
    old = new Date().valueOf()
    timeout = null
    result = func.apply(context, args)
  }
  let trottled = function () {
    context = this
    args = arguments
    let now = new Date().valueOf()
    if (options.leading === false  && !old) {
      old = now;
    }
    if (now - old > wait) {
      if (timeout) {
        clearTimeout(timeout)
        timeout = null 
      }
      result = func.apply(context, args)
      old = now
    }

    if (!timeout && options.trailing !== false) {
      timeout = setTimeout(later, wait)
    }
    return result
  }
  trottled.cancel = function () {
    clearTimeout(timeout)
    timeout = null
  }
  return trottled
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值