函数节流之debounce

  浏览器中某些计算和处理要比其他的昂贵很多。例如, DOM 操作比起非 DOM 交互需要更多的内存和 CPU 时间。连续尝试进行过多的 DOM 相关操作可能会导致浏览器挂起,有时候甚至会崩溃。尤其在 IE 中使用 onresize 事件处理程序的时候容易发生,当调整浏览器大小的时候,该事件会连续触发。在 onresize 事件处理程序内部如果尝试进行 DOM 操作,其高频率的更改可能会让浏览器崩溃。为了绕开这个问题,你可以使用定时器对该函数进行节流。 

  函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个 (摘录至JavaScript高级程序设计的函数节流)。

适用的应用场景:

1、window对象的resize、scroll事件

2、拖拽时的mousemove事件

3、射击游戏中的mousedown、keydown事件

4、文字输入、自动完成的keyup事件

 1 /**
 2  * 函数去抖,保证在一段时间内,被调用函数只是执行一次
 3  * @param {*} func 调用用的函数,function
 4  * @param {*} wait 等待的时间,单位ms
 5  * @param {*} immediate  当immediate为true时,第一次调用该函数的时候,就调用func函数;false表示超时之后再调用
 6  */
 7 export function debounce (func, wait, immediate = false) {
 8   let timeout, args, context, timestamp, result
 9 
10   const later = function () {
11     // 记录上一次触发时间间隔
12     const last = +new Date() - timestamp
13 
14     // 上次被包装函数被调用时间间隔last小于设定时间间隔wait
15     // 调用的时间比较频繁,重新计算下次执行的时间
16     if (last < wait && last > 0) {
17       timeout = setTimeout(later, wait - last)
18     } else {
19       timeout = null
20       // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
21       if (!immediate) {
22         result = func.apply(context, args)
23         if (!timeout) context = args = null
24       }
25     }
26   }
27 
28   // ...args:使用es6的rest运算符,把逗号隔开的值序列组合成一个数组:如test(1,2,3,4) ==> args:[1,2,3,4]
29   // 符合apply(obj,[])
30   return function (...args) {
31     // 把上下文的this对象保存下来,因为下面的apply要使用
32     context = this
33     // 记录当前的时间戳,也可以使用Date.now()
34     timestamp = +new Date()
35     // 第一次调用该方法时,且immediate为true,则调用func函数
36     const callNow = immediate && !timeout
37     // 如果延时不存在,重新设定延时,首次的时候
38     if (!timeout) {
39       timeout = setTimeout(later, wait)
40     }
41     // 如果immediate为true,那么立马调用该函数
42     if (callNow) {
43       result = func.apply(context, args)
44       context = args = null
45     }
46 
47     return result
48   }
49 }

 

原文地址:https://www.cnblogs.com/llcdxh/p/9329084.html