UNPKG

2.89 kBJavaScriptView Raw
1"use strict";
2const pDefer = require("p-defer");
3function mapAgeCleaner(map, property = 'maxAge') {
4 let processingKey;
5 let processingTimer;
6 let processingDeferred;
7 const cleanup = async () => {
8 if (processingKey !== undefined) {
9 // If we are already processing an item, we can safely exit
10 return;
11 }
12 const setupTimer = async (item) => {
13 processingDeferred = pDefer();
14 const delay = item[1][property] - Date.now();
15 if (delay <= 0) {
16 // Remove the item immediately if the delay is equal to or below 0
17 map.delete(item[0]);
18 processingDeferred.resolve();
19 return;
20 }
21 // Keep track of the current processed key
22 processingKey = item[0];
23 processingTimer = setTimeout(() => {
24 // Remove the item when the timeout fires
25 map.delete(item[0]);
26 if (processingDeferred) {
27 processingDeferred.resolve();
28 }
29 }, delay);
30 // tslint:disable-next-line:strict-type-predicates
31 if (typeof processingTimer.unref === 'function') {
32 // Don't hold up the process from exiting
33 processingTimer.unref();
34 }
35 return processingDeferred.promise;
36 };
37 try {
38 for (const entry of map) {
39 await setupTimer(entry);
40 }
41 }
42 catch (_a) {
43 // Do nothing if an error occurs, this means the timer was cleaned up and we should stop processing
44 }
45 processingKey = undefined;
46 };
47 const reset = () => {
48 processingKey = undefined;
49 if (processingTimer !== undefined) {
50 clearTimeout(processingTimer);
51 processingTimer = undefined;
52 }
53 if (processingDeferred !== undefined) { // tslint:disable-line:early-exit
54 processingDeferred.reject(undefined);
55 processingDeferred = undefined;
56 }
57 };
58 const originalSet = map.set.bind(map);
59 map.set = (key, value) => {
60 if (map.has(key)) {
61 // If the key already exist, remove it so we can add it back at the end of the map.
62 map.delete(key);
63 }
64 // Call the original `map.set`
65 const result = originalSet(key, value);
66 // If we are already processing a key and the key added is the current processed key, stop processing it
67 if (processingKey && processingKey === key) {
68 reset();
69 }
70 // Always run the cleanup method in case it wasn't started yet
71 cleanup(); // tslint:disable-line:no-floating-promises
72 return result;
73 };
74 cleanup(); // tslint:disable-line:no-floating-promises
75 return map;
76}
77module.exports = mapAgeCleaner;