美文网首页
JavaScript 之函数防抖

JavaScript 之函数防抖

作者: 临安linan | 来源:发表于2019-11-08 20:01 被阅读0次

更多个人博客:(https://github.com/zenglinan/blog)

如果对你有帮助,欢迎star。

防抖的原理: 为了避免事件频繁触发执行, 让事件只有在触发后 n 秒才执行, 假如 n 秒内重新触发了事件, 则刷新时间戳, 在下一个 n 秒后执行
使用方式大概是: dom.onmousemove = debounce(getUserAction, 1000);

基础版防抖: 输入指定时间, 实现防抖

function debounce(fn, time){
  let timer
  return function(){
    clearTimeout(timer)
    timer = setTimeout(fn, time)
  }
}

只要在 time 内重新触发了事件, 定时器就会被清除掉, 重新开启下一个。

改良版

上一版实现了基础代码, 但是还有些地方需要完善, 比如:

  1. this 指向被改变了, 需要保证 fn 内部的 this 指向触发元素本身
  2. 需要提供 event 对象

    这里为了保证 this, 采用箭头函数, 同时将 arguments 参数对象传入, 保证 event 对象可以获取到
function debounce(fn, time){
  let timer
  return function(){
    // 事件触发时这里的 this 指向的是元素
    let args = arguments  // 取出的参数对象里包含了 event 对象
    clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, args)
    }, time)
  }
}

立即执行

以上, 我们的防抖函数已经比较完备了

但是还可以添加一个需求使之更完善:

不要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行

这里用一个可选参数来决定是否要采取这种立即触发的模式

function debounce(fn, time, immediate){
  let timer
  return function(){
    let args = arguments
    clearTimeout(timer)

    if(immediate){  // 采取立即执行模式
      let callNow = !timer  // 只有 timer 为 falsy 值时, 才立即执行
      timer = setTimeout(()=>{
        timer = null  // 只要 time 时间不触发, 就把 timer 设为 null, 那么下一次就会直接执行了
      }, time)
      callNow && fn.apply(this, args)
    }
    
    else{  // 采取传统模式
      timer = setTimeout(() => {
        fn.apply(this, args)
      }, time)
    }
  }
}

思路剖析: 当传入第三个参数为 true 时, 开启立即执行模式, 第一次的时候 timer 肯定为 undefined, 这时候 callNow 为 true, 立即执行

与此同时, 给 timer 赋值定时器, 这时候 timer 就不是 falsy 值了, 如果马上再触发一次, !timer 为false, 不会马上执行

同时, timer 设置的定时器里, time 时间后就会把 timer 重置为 null, 但是每次触发都会清除这个定时器, 所以只要在 time 时间内不去触发, 再下次触发时, !timer 就会为 true, 就能立即执行了

要注意: 定时器返回给 timer 的是数字, 即使清除了定时器, timer 的值也不会被清除, 只有手动赋值才能让其为 falsy 值。

可取消

这里还可以再完善一下, 添加重置 debounce 函数的功能,

假如说 debounce 的时间间隔是 10 s, immediate 为 true, 我只有等 10 秒后才能重新触发事件

我希望有时能够立即重置防抖, 即回到立即执行的状态。

只需添加一个取消函数来重置 timer 即可

function debounce(fn, time, immediate){
  let timer
  var debounceFn = function(){
    let args = arguments
    clearTimeout(timer)

    if(immediate){
      let callNow = !timer
      timer = setTimeout(()=>{
        timer = null
      }, time)
      callNow && fn.apply(this, args)
    }
    
    else{
      timer = setTimeout(() => {
        fn.apply(this, args)
      }, time)
    }
  }
  debounceFn.reset = function(){  // 取消函数, 注意: 取消完后又恢复
    clearTimeout(timer)
    timer = null
  }
  return debounceFn
}

使用的时候需要这样使用

let debounced = debounce(fn, 1000)
dom.onmousemove = debounced
// 重置函数的使用方法
button.onclick = debounced.reset

参考: https://github.com/mqyqingfeng/Blog/issues/22

相关文章

  • Javascript 基础

    1、函数防抖和函数节流 【《javascript高级程序设计》里,函数节流是这里讲的函数防抖。】函数防抖: 在事件...

  • JavaScript 之函数防抖

    更多个人博客:(https://github.com/zenglinan/blog) 如果对你有帮助,欢迎star...

  • JS笔试题

    JavaScript 笔试部分 实现防抖函数(debounce) 防抖函数原理:在事件被触发 n 秒后再执行回调,...

  • 分享:22道JavaScript高频手写面试题

    JavaScript笔试部分 实现防抖函数(debounce) 防抖函数原理:在事件被触发n秒后再执行回调,如果在...

  • 函数防抖与函数节流

    debounce -- 函数防抖,throttle -- 函数节流都是在JavaScript中可以限制函数发生频率...

  • 函数防抖和函数节流

    函数防抖和函数节流 函数防抖和函数节流:是优化高频率执行的JavaScript代码的一种手段。常用于JavaScr...

  • 彻底弄懂函数防抖和函数节流

    函数防抖和节流 函数防抖和函数节流:是优化高频率执行的JavaScript代码的一种手段。常用于JavaScrip...

  • JavaScript之函数防抖、节流

    一、前言 相信无论在实际应用场景、亦或是面试,都会经常遇得到函数防抖、函数节流等,下面我们来聊一聊吧。 先放出一个...

  • javaScript 防抖函数

    一. 防抖函数的定义与使用 防抖函数的定义 防抖函数的调用 二. 防抖函数应用场景 其实在HTML 和javaSc...

  • JavaScript函数防抖

    一、前言 一如寄往的没有原因,没有前言,就是想整理一篇《函数防抖》和《函数节流》的相关知识,当然在工作和面试中遇到...

网友评论

      本文标题:JavaScript 之函数防抖

      本文链接:https://www.haomeiwen.com/subject/wciwbctx.html