blob: 68ce44909b7d9567fb2dcda42e6a5709ec40fb0a [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001/**
2 * Debouncing enforces that a function not be called again until a certain
3 * amount of time has passed without it being called.
4 *
5 * @see https://css-tricks.com/the-difference-between-throttling-and-debouncing/
6 * @see https://github.com/webmodules/raf-debounce
7 * @see https://github.com/moszeed/es6-promise-debounce
8 * @see https://gist.github.com/philbirnie/893950093611d5c1dff4246a572cfbeb/
9 * @see https://github.com/SliceMeNice-ES6/event-utils/blob/master/debounce.js
10 * @see https://github.com/jeromedecoster/raf-funcs
11 * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
12 * @see http://davidwalsh.name/javascript-debounce-function
13 *
14 * @param callback the callback
15 * @param threshold optional delay, default to 250 ms, min to 1000/60ms ms
16 * @param context optional context of this, default to global
17 * @return {Function} reference to immediate and cancel
18 */
19const MIN_THRESHOLD = 1000/60;
20
21const debounceFunction = function(callback, threshold=250, context) {
22
23 if(threshold < MIN_THRESHOLD) {
24 threshold = MIN_THRESHOLD;
25 }
26
27 if (!context) {
28 context = this || window;
29 }
30
31 let next = null;
32 let start = 0;
33
34 return function (...args) {
35
36 const cancel = () => {
37 if(next) {
38 window.cancelAnimationFrame(next);
39 next = null;
40 }
41 };
42
43 const execute = () => {
44 cancel();
45 return Reflect.apply(callback, context, args);
46 };
47
48 const later = () => {
49 if (threshold - (Date.now() - start) <= 0) {
50 return execute();
51 }
52 next = window.requestAnimationFrame(later);
53 };
54
55 cancel();
56 start = Date.now();
57 next = window.requestAnimationFrame(later);
58
59 return {
60 cancel: () => cancel(),
61 immediate: () => execute()
62 };
63 };
64};
65
66export default debounceFunction;