-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy paththrottle.js
93 lines (82 loc) · 2.55 KB
/
throttle.js
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
'use strict';
var timerCache = {};
/**
* Throttle a callback. `callback` executes synchronously only if
* more than `minInterval` milliseconds have already elapsed since the latest
* call (if any). Otherwise we wait until `minInterval` is over and execute the
* last callback received while waiting.
* So the first and last events in a train are always executed (eventually)
* but some of the events in the middle can be dropped.
*
* @param {string} id: an identifier to mark events to throttle together
* @param {number} minInterval: minimum time, in milliseconds, between
* invocations of `callback`
* @param {function} callback: the function to throttle. `callback` itself
* should be a purely synchronous function.
*/
exports.throttle = function throttle(id, minInterval, callback) {
var cache = timerCache[id];
var now = Date.now();
if(!cache) {
/*
* Throw out old items before making a new one, to prevent the cache
* getting overgrown, for example from old plots that have been replaced.
* 1 minute age is arbitrary.
*/
for(var idi in timerCache) {
if(timerCache[idi].ts < now - 60000) {
delete timerCache[idi];
}
}
cache = timerCache[id] = {ts: 0, timer: null};
}
_clearTimeout(cache);
function exec() {
callback();
cache.ts = Date.now();
if(cache.onDone) {
cache.onDone();
cache.onDone = null;
}
}
if(now > cache.ts + minInterval) {
exec();
return;
}
cache.timer = setTimeout(function() {
exec();
cache.timer = null;
}, minInterval);
};
exports.done = function(id) {
var cache = timerCache[id];
if(!cache || !cache.timer) return Promise.resolve();
return new Promise(function(resolve) {
var previousOnDone = cache.onDone;
cache.onDone = function onDone() {
if(previousOnDone) previousOnDone();
resolve();
cache.onDone = null;
};
});
};
/**
* Clear the throttle cache for one or all timers
* @param {optional string} id:
* if provided, clear just this timer
* if omitted, clear all timers (mainly useful for testing)
*/
exports.clear = function(id) {
if(id) {
_clearTimeout(timerCache[id]);
delete timerCache[id];
} else {
for(var idi in timerCache) exports.clear(idi);
}
};
function _clearTimeout(cache) {
if(cache && cache.timer !== null) {
clearTimeout(cache.timer);
cache.timer = null;
}
}