一 防抖

防抖函数 debounce 指的是某个函数在某段时间内,无论触发了多少次回调,都只执行最后一次。假如我们设置了一个等待时间 3 秒的函数,在这 3 秒内如果遇到函数调用请求就重新计时 3 秒,直至新的 3 秒内没有函数调用请求,此时执行函数,不然就以此类推重新计时。

原理及实现

实现原理就是利用定时器,函数第一次执行时设定一个定时器,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。

实现 1

  1. // 实现 1
  2. // fn 是需要防抖处理的函数
  3. // wait 是时间间隔
  4. function debounce(fn, wait = 50) {
  5. // 通过闭包缓存一个定时器 id
  6. let timer = null
  7. // 将 debounce 处理结果当作函数返回
  8. // 触发事件回调时执行这个返回函数
  9. return function() {
  10. let self = this
  11. let args = arguments;
  12. // 如果已经设定过定时器就清空上一次的定时器
  13. if (timer) clearTimeout(timer)
  14. // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn
  15. timer = setTimeout(function() {
  16. fn.apply(self, args)
  17. }, wait)
  18. }
  19. }
  20. // DEMO
  21. // 执行 debounce 函数返回新函数
  22. const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000)
  23. // 停止滑动 1 秒后执行函数 () => console.log('fn 防抖执行了')
  24. document.addEventListener('scroll', betterFn)

实现 2

实现原理比较简单,判断传入的 immediate 是否为 true,另外需要额外判断是否是第一次执行防抖函数,判断依旧就是 timer 是否为空,所以只要 immediate && !timer 返回 true 就执行 fn 函数,即 fn.apply(this, args)

  1. // 实现 2
  2. // immediate 表示第一次是否立即执行
  3. function debounce(func, wait = 50, immediate) {
  4. var timer, result;
  5. var debounced = function () {
  6. var context = this;
  7. var args = arguments;
  8. if (timer) clearTimeout(timer);
  9. if (immediate) {
  10. // 如果已经执行过,不再执行
  11. var callNow = !timer;
  12. // 最后停止后 过了 wait 时间在执行 并清除timer
  13. timer = setTimeout(function(){
  14. timer = null;
  15. result = func.apply(context, args)
  16. }, wait)
  17. if (callNow) result = func.apply(context, args)
  18. }
  19. else {
  20. timer = setTimeout(function(){
  21. timer = null;
  22. func.apply(context, args)
  23. }, wait);
  24. }
  25. return result;
  26. };
  27. // 取消防抖
  28. debounced.cancel = function() {
  29. clearTimeout(timer);
  30. timer = null;
  31. };
  32. // 返回值
  33. return debounced;
  34. }
  35. // DEMO
  36. // 执行 debounce 函数返回新函数
  37. const betterFn = debounce(() => console.log('fn 防抖执行了'), 1000, true)
  38. // 第一次触发 scroll 执行一次 fn,后续只有在停止滑动 1 秒后才执行函数 fn
  39. document.addEventListener('scroll', betterFn)

二 节流

节流的原理:连续触发事件,每隔一段时间,只执行一次事件。

使用时间戳实现

当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。

  1. function throttle(func, wait) {
  2. var context, args;
  3. var previous = 0;
  4. return function() {
  5. var now = +new Date();
  6. context = this;
  7. args = arguments;
  8. if (now - previous > wait) {
  9. func.apply(context, args);
  10. previous = now;
  11. }
  12. }
  13. }

使用定时器

  1. function throttle(func, wait) {
  2. var timeout;
  3. var previous = 0;
  4. return function() {
  5. context = this;
  6. args = arguments;
  7. if (!timeout) {
  8. timeout = setTimeout(function(){
  9. timeout = null;
  10. func.apply(context, args)
  11. }, wait)
  12. }
  13. }
  14. }