首先,我们先来了解一下什么是防抖和节流。
防抖(debounce)
函数防抖,这里的抖动就是执行的意思,而一般的抖动都是持续的,多次的。假设函数持续多次执行,我们希望让它冷静下来再执行。也就是当持续触发事件的时候,函数是完全不执行的,等最后一次触发结束的一段时间之后,再去执行
特点:
- 持续触发不执行
- 最后一次触发过了一段时间之后再执行
我们写 js 的时候通常会这么来写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function debounce(fn, delay) { let timer = null return function () { if (timer) { clearTimeout(timer); } timer = setTimeout(fn, delay); }; }
function test(){ console.log('test') }
window.onscroll = debounce(test, 1000);
|
节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。节流会稀释函数的执行频率。
说的通俗一点就是设计一种类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)。
特点:
- 如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效.
js中我们的常见写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function throttle(fun, wait) { let timeout = null; return function() { if (!timeout) { timeout = setTimeout(function(){ timeout = null; fun() }, wait) } } } function test(){ console.log('test') }
window.onscroll = throttle(test, 500);
|
进阶(TS装饰器)
在你阅读这节之前,希望你已经了解了TS基础以及装饰器的基本用法。
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| const delayDefault = 500;
export const debounce = (delay = delayDefault) => { return function(target, key, descriptor) { const oldValue = descriptor.value; let timer: any = null; descriptor.value = function() { clearTimeout(timer); timer = setTimeout(() => { oldValue.apply(this, arguments); }, delay); }; return descriptor; }; };
export const throttle = (delay = delayDefault) => { return function(target, key, descriptor) { let lastTime, timer; const oldFunction = descriptor.value; descriptor.value = function() { let nowTime = +new Date(); if (lastTime && nowTime - lastTime < delay) { if (timer) { clearTimeout(timer); } timer = setTimeout(() => { oldFunction.apply(this, arguments); lastTime = nowTime; }, delay); } else { oldFunction.apply(this, arguments); lastTime = nowTime; } }; return descriptor; }; };
export const throttle = (delay = delayDefault) => { return function(target, key, descriptor) { let timer: any = null; const oldFunction = descriptor.value; descriptor.value = function() { if (!timer) { timer = setTimeout(() => { timer = null; oldFunction.apply(this, arguments); }, delay); } }; return descriptor; }; };
|
以上两种节流都可正常使用,没有好坏之分,看个人喜好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Test{
@debounce() funA(){ console.log('A') }
@throttle() funB(){ console.log('B') }
}
|