This repository has been archived by the owner on Feb 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecorator.debounce-throttle.ts
76 lines (74 loc) · 3.54 KB
/
decorator.debounce-throttle.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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* To add debounce or throttle support by adding decorator (@debounce_throttle(args)) before original function
* @author LouisSung <[email protected]> All Rights Reserved
* @version v1.0.1 (2019.12.11) (Bug fix)
* @licence MIT
*
* @param wait - Waiting time for the next valid event
* @param immediate - Trigger time (true: immediate, false: after: waiting time)
* @param limit - (For throttle only) Guarantee the execution (in `$limit` ms) even if the events keep happening
* Set as `0` to degrade to `debounce` (default)
*/
export function debounce_or_throttle(wait: number = 1000, immediate = true, limit = 0): MethodDecorator {
// ref: https://css-tricks.com/debouncing-throttling-explained-examples/
// ref: https://stackoverflow.com/a/35527852
// ref@comment@jcdsr: https://plnkr.co/edit/3J0dcDaLTJBxkzo8Akyg?p=preview
// ref: https://kanboo.github.io/2018/05/03/JS-debounce-throttle
return (target: object, propertyKey: string, descriptor: PropertyDescriptor) => {
const origFunc = descriptor.value;
let timerID: number = null;
let startTime: number = null;
/** Use throttle if `0 < limit < wait`; otherwise, use debounce instead */
if (0 < limit && limit < wait) {
descriptor.value = function _dummy(this: any, ...args: any[]) {
// discard old event timer
clearTimeout(timerID);
const currentTime: number = new Date().getTime();
// set up throttle (the first one or the new one after waiting time)
if (timerID === null) {
startTime = currentTime;
console.log('> start throttle: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
if (immediate === true) {
console.log('>> (fire) immediate: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
origFunc.apply(this, args);
}
}
// check if $limit exceeded (discard the old waiting timer)
if (currentTime - startTime >= limit) {
startTime = currentTime;
console.log('>> (fire) reach the time limit: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
origFunc.apply(this, args);
} else {
timerID = setTimeout(() => { // function waitFunc()
console.log('>> (throttle) waiting time exceeded !!', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
if (immediate === false) {
console.log('>> (fire) delayed: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
origFunc.apply(this, args);
}
timerID = null;
}, wait);
}
};
} else {
descriptor.value = function _dummy(this: any, ...args: any[]) {
clearTimeout(timerID);
if (timerID === null) {
console.log('> start debounce: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
if (immediate === true) {
console.log('>> (fire) immediate: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
origFunc.apply(this, args);
}
}
timerID = setTimeout(() => {
console.log('>> (debounce) waiting time exceeded !!', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
if (immediate === false) {
console.log('>> (fire) delayed: ', new Date().getSeconds(), 's', new Date().getMilliseconds(), 'ms');
origFunc.apply(this, args);
}
timerID = null;
}, wait);
};
}
return descriptor;
};
}