/* MAIN */ // Registering a single interval scales much better than registering N timeouts // Timeouts are respected within the interval margin const WatcherLocksResolver = { /* VARIABLES */ interval: 100, intervalId: undefined, fns: new Map(), /* LIFECYCLE API */ init: () => { if (WatcherLocksResolver.intervalId) return; WatcherLocksResolver.intervalId = setInterval(WatcherLocksResolver.resolve, WatcherLocksResolver.interval); }, reset: () => { if (!WatcherLocksResolver.intervalId) return; clearInterval(WatcherLocksResolver.intervalId); delete WatcherLocksResolver.intervalId; }, /* API */ add: (fn, timeout) => { WatcherLocksResolver.fns.set(fn, Date.now() + timeout); WatcherLocksResolver.init(); }, remove: (fn) => { WatcherLocksResolver.fns.delete(fn); }, resolve: () => { if (!WatcherLocksResolver.fns.size) return WatcherLocksResolver.reset(); const now = Date.now(); for (const [fn, timestamp] of WatcherLocksResolver.fns) { if (timestamp >= now) continue; // We should still wait some more for this WatcherLocksResolver.remove(fn); fn(); } } }; /* EXPORT */ export default WatcherLocksResolver;