函数防抖与节流

函数防抖与节流

平常工做中,常常遇到这样一个问题,在滚动事件中须要作个复杂计算或者实现一个按钮的防二次点击操做。javascript

  • 防抖和节流的做用都是防止函数屡次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的状况下只会调用一次,而节流的 状况会每隔必定时间(参数wait)调用函数。

函数防抖(debounce)

  • 例如在搜索引擎搜索问题的时候,咱们是但愿用户输入完最后一个字才调用查询接口,这个时候适用延迟执行的防抖函数,它老是在一连串(间隔小于wait的)函数触发以后调用。
const debounce = (fn, wait = 800) => {
    let timer = null
    return function() {
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        // 用 .apply 保证 sayHi 里面的 this 指向事件的调用者,不然指向 window
        fn.apply(this, arguments)
      }, wait);
    }
  }
 
 function sayHi() {
     console.log('防抖成功')
 }
 
let inp = document.querySelector('#input')

inp.addEventListener('input', debounce(sayHi))

复制代码
  • 上面这个函数有一点缺陷:会存在一种当即执行函数,好比(咱们在点击 star 的时候,但愿是点击第一次的时候就生效,而不是最后一次生效)。改进以下:
const debounce = (fn, wait = 800, immediate = true) => {
    let timer, context, args

    // 延迟执行函数
    const later = () => setTimeout(() => {
    // 延迟函数执行完毕,清空缓存的定时器序号
      timer = null
      if (!immediate) {
        fn.apply(context, args)
        context = args = null
      }
    }, wait);

    // 返回的函数是每次实际调用的函数
    return function(...params) {
      // 若是没有建立延迟函数 later, 就建立一个
      if (!timer) {
        timer = later()
        // 如果当即执行函数,则调用函数
        // 不然缓存参数和调用上下文
        if (immediate) {
          fn.apply(this, params)
        } else {
          context = this
          args = params
        }

         // 若是已经有延迟执行函数 (later), 调用的时候清除原来的并从新设定一个
      } else {
        clearTimeout(timer)
        timer = later()
      }
    }
  }

  function sayHi() {
    console.log(this);
    console.log('防抖成功');
  }

  let inp = document.querySelector('#input')

  inp.addEventListener('input', debounce(sayHi))
复制代码

函数节流(throttle)

  • 防抖动是将屡次执行变为最后一次执行,节流是将屡次执行变成每隔一段时间执行。
const throttle = (fn, wait = 400) => {
  let canRun = true
  return function (...args) {
    if (!canRun) return
    canRun = false

    setTimeout(() => {
      fn.apply(this, args)
      // 最后在 setTimeout 执行完毕后再把标记设置为 true (关键)表示能够执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头被 return 掉
      canRun = true
    }, wait);
  }
}

function sayHi() {
    console.log(this);
    console.log('节流成功');
  }

let inp = document.querySelector('#input')

inp.addEventListener('input', throttle(sayHi))
复制代码

总结(使用场景):java

函数防抖:npm

  • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
  • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

函数节流:浏览器

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次);
  • 监听滚动事件,好比是否滑到底部自动加载更多,用throttle来判断

PS: 生产环境中,建议用 lodash 中的 debouncethrottle。毕竟那么多人在用,出现问题的几率会很小。缓存

相关文章
相关标签/搜索