I have a use case where I have multiple functions firing simultaneously. Each function can be called multiple times but I need to pick out only one return value. Im using debounce and it does work as intended. Even if I have 10 return values, I get only 1 return at the end. However if there are unique values, I want all the unique values returned
What is happening
-----1----2-----2---2----2----2----3-----3---3---3---3---3------>
(Only 1 value is returned)
-------------------3--------------------------------------------->
What I want
-----1----2-----2----2----2----2----3-----3---3---3---3---3------>
(Return all unique values)
-------------------1-------------------2--------------------3---->
What I have tried (Example)
var _ = require('lodash');
function printOne () {
handleDebounce(1);
}
function printTwo () {
handleDebounce(2);
}
function printThree () {
handleDebounce(3);
}
const handleDebounce = _.debounce((msg) => {
console.log(msg)
}, 2000, );
printOne();
printTwo();
printTwo();
printTwo();
printThree();
printThree();
printThree();
Output -> 3
Expected Output -> 1 2 3
Should I use a set to have a form of local cache and then get unique values? Any pointers would be welcome
CodePudding user response:
You could keep track of all the arguments that were passed to the function. You could do this in a nested lookup Map, where each nested level is about a next argument (in case multiple arguments are passed). A special end-symbol indicates that an argument in that nested Map was the final argument -- to differentiate cases where the same arguments were passed, but with some extra arguments following those.
Here is how that could be implemented:
function withUniqueArguments(func, delay=50) {
const end = Symbol("end"); // A unique value only known here
const map = new Map; // Stores all argument references used before
function testAndSetArgs(args) {
let node = map;
for (const arg of args) {
let res = node.get(arg);
if (res === undefined) node.set(arg, res = new Map);
node = res;
}
let found = node.get(end);
if (!found) node.set(end, true);
return !!found;
}
return function wrapper(...args) {
if (testAndSetArgs(args)) return; // Function was called with these arguments before
setTimeout(() => func.call(this, ...args), delay);
};
}
const handleSearch = withUniqueArguments(console.log, 50);
handleSearch(1);
handleSearch(2);
handleSearch(2);
handleSearch(2);
handleSearch(3);
handleSearch(3);
handleSearch(3);
Disclaimer: the comparison of arguments is reference-based, so if objects are passed as arguments, they will only be regarded the same when they are really the same object, not copies of them. Also, when an object is mutated between calls, and passed again as argument, it will still be considered the same object, and so no second call will be made.
If you need copied objects to be considered the same, and mutated objects to be considered different, then you need to include a deep-object-comparison function.