UNPKG

2.21 kBJavaScriptView Raw
1import clear from './clear.js';
2import delay from './delay.js';
3
4/**
5 * Returns a new debounced function that waits to call the callback until `duration` ms have passed since the last time it was called.
6 *
7 * @example
8 * ``` javascript
9 * import { debounce } from 'async-agent';
10 *
11 * const debounced = debounce(() => {
12 * console.log('1');
13 * });
14 *
15 * debounced();
16 * debounced();
17 * debounced();
18 * debounced();
19 *
20 * // => 1
21 * ```
22 *
23 * @function debounce
24 *
25 * @arg {Function} callback - The context and args from the last call will be passed in.
26 * @arg {Number} [duration=0]
27 * @arg {Object} [options={}]
28 * @arg {Boolean} [options.leading=false] - If true then the callback is called immediately the first time.
29 * @arg {Boolean} [options.maxWait] - Max time to wait before flushing.
30 * @arg {Boolean} [options.trailing=true] - If false then the callback will only be called on the leading edge.
31 *
32 * @returns {Function} The debounced function. Has two methods: .clear() clears any current timeouts, and .flush() immediately calls any waiting callbacks.
33 */
34export default (callback, duration = 0, options = {}) => {
35 let timeout;
36 let maxTimeout;
37 let isLeading = false;
38 let context;
39 let lastArgs;
40
41 if (options.trailing === false) {
42 options.leading = true;
43 }
44
45 const call = () => {
46 isLeading = options.leading;
47 callback.apply(context, lastArgs);
48 if (isLeading) {
49 timeout = delay(debounced.clear, duration);
50 }
51 };
52
53 const debounced = function(...args) {
54 context = this;
55 lastArgs = args;
56
57 if (options.leading && !timeout) {
58 call();
59 }
60 else {
61 isLeading = false;
62 debounced.clear();
63 timeout = delay(debounced.flush, duration);
64 }
65
66 if (options.maxWait && !maxTimeout) {
67 maxTimeout = delay(debounced.flush, options.maxWait);
68 }
69 };
70
71 debounced.clear = () => {
72 if (timeout) {
73 clear(timeout);
74 timeout = null;
75 }
76 };
77
78 debounced.flush = () => {
79 if (timeout) {
80 debounced.clear();
81
82 if (maxTimeout) {
83 clear(maxTimeout);
84 maxTimeout = null;
85 }
86
87 if (options.trailing !== false && !isLeading) {
88 call();
89 }
90 }
91 };
92
93 return debounced;
94};