平时 coding 的时候总是会用到这两个函数,但是一直没有仔细研究过它们俩到底有什么区别,最近抽空学习了一下 lodash 中这两个函数的源码,以下是这次学习的总结。
Debounce
debounce 创建了一个在上一次函数执行结束后等待一定时间,之后才执行的防反跳函数。
以电梯为例,电梯设置了等待 10秒 运行,这时候进来一个人,那么按照 debounce 的逻辑,需再等 10 秒,电梯才会运行。
在工作中,曾经遇到一个需求就是监测用户键入,当用户键入停止就保存草稿。
如果不用 debounce, 那么每次 keyup 都会发起一次请求,这样会大大增加服务器的压力;使用了 debounce, 设定 wait 3 秒,那么在用户停止键入之后,等待 3 秒,如果用户没有继续键入,就保存草稿,如果再次键入,那么就继续等待。这样就节省了大量的请求,也就减轻了服务器的压力。
在 lodash 中,debounce 函数的源码大体如下(省略了部分函数的详细代码):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| // 参数:func 需要使用debounce防止多次短时间多次执行的函数 // 参数: wait 最大等待时间 // 参数:options对象,有leading、trailing和maxWait参数。 // leading, 默认为false,表示首次调用的时候需要执行函数; // trailing, 默认为true,表示等待特定时间之后执行 // 有一应用场景,就是设置leading:true; trailng: fals,用于发送请求的时候防止连续点击。 // 方法:cancel 用于取消限制执行次数 // 方法:flush 立即执行 function debounced(func, wait, { leading: false, trailing }) { const time = Date.now() // 根据时间判断是否已经可以执行函数 const isInvoking = shouldInvoke(time) lastArgs = args lastThis = this lastCallTime = time if (isInvoking) { // 如果还没有定时器,那就是第一次触发事件,通过leading参数判断第一次触发时需不需要执行 if (timerId === undefined) { return leadingEdge(lastCallTime) } // 有参数maxWait, maxing由maxWait计算得来,这里省略 // 如果已经过了最大等待时间,那么执行函数,并且重新定时 if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait) return invokeFunc(lastCallTime) } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait) } return result } debounced.cancel = cancel debounced.flush = flush
|
Throttle
throttle 是节流的意思,throttle 函数也是用阻止函数在短时间内多次调用。具体实现,就是在当前函数执行之后,等待特定时间之后再次执行,不管中间函数被调用多少次。
还是以电梯为例,电梯设定 10 秒运行一次。那么到达 10 秒,电梯就会马上运行,如果这时候有人要进,也不会等待。
在平时工作中,也有应用场景,如鼠标拖拽。一般拖拽的时候会要求 拖拽的元素一直跟随鼠标上下左右动。这里就会涉及大量的 DOM 渲染,而我们知道 DOM 渲染是极耗性能的,
很可能会导致浏览器卡顿,在 IE 中甚至会导致浏览器崩溃。使用 throttle,就可以在用户可接受的时间间隔内限制事件的触发次数,极大的减少性能的消耗。
下面我们看一下 lodash 中 throttle 的实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function throttle(func, wait, options) { let leading = true let trailing = true if (typeof func != 'function') { throw new TypeError('Expected a function') } if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading trailing = 'trailing' in options ? !!options.trailing : trailing } return debounce(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }) }
|
可以发现,其实在 lodash 中,throttle 就是 maxWait 等于 wait,并且 leading 为 true 的 debounce 函数的特例。同样的,throttle 也有 cancel 和 flush 方法。
参考:
http://www.alloyteam.com/2012/11/javascript-throttle/
JS 高级程序设计