UNPKG

2.14 kBJavaScriptView Raw
1function debounce(function_, wait = 100, options = {}) {
2 if (typeof function_ !== 'function') {
3 throw new TypeError(`Expected the first parameter to be a function, got \`${typeof function_}\`.`);
4 }
5
6 if (wait < 0) {
7 throw new RangeError('`wait` must not be negative.');
8 }
9
10 // TODO: Deprecate the boolean parameter at some point.
11 const {immediate} = typeof options === 'boolean' ? {immediate: options} : options;
12
13 let storedContext;
14 let storedArguments;
15 let timeoutId;
16 let timestamp;
17 let result;
18
19 function later() {
20 const last = Date.now() - timestamp;
21
22 if (last < wait && last >= 0) {
23 timeoutId = setTimeout(later, wait - last);
24 } else {
25 timeoutId = undefined;
26
27 if (!immediate) {
28 const callContext = storedContext;
29 const callArguments = storedArguments;
30 storedContext = undefined;
31 storedArguments = undefined;
32 result = function_.apply(callContext, callArguments);
33 }
34 }
35 }
36
37 const debounced = function (...arguments_) {
38 if (storedContext && this !== storedContext) {
39 throw new Error('Debounced method called with different contexts.');
40 }
41
42 storedContext = this; // eslint-disable-line unicorn/no-this-assignment
43 storedArguments = arguments_;
44 timestamp = Date.now();
45
46 const callNow = immediate && !timeoutId;
47
48 if (!timeoutId) {
49 timeoutId = setTimeout(later, wait);
50 }
51
52 if (callNow) {
53 const callContext = storedContext;
54 const callArguments = storedArguments;
55 storedContext = undefined;
56 storedArguments = undefined;
57 result = function_.apply(callContext, callArguments);
58 }
59
60 return result;
61 };
62
63 debounced.clear = () => {
64 if (!timeoutId) {
65 return;
66 }
67
68 clearTimeout(timeoutId);
69 timeoutId = undefined;
70 };
71
72 debounced.flush = () => {
73 if (!timeoutId) {
74 return;
75 }
76
77 const callContext = storedContext;
78 const callArguments = storedArguments;
79 storedContext = undefined;
80 storedArguments = undefined;
81 result = function_.apply(callContext, callArguments);
82
83 clearTimeout(timeoutId);
84 timeoutId = undefined;
85 };
86
87 return debounced;
88}
89
90// Adds compatibility for ES modules
91module.exports.debounce = debounce;
92
93module.exports = debounce;