0

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

VLAZ
  • 26,331
  • 9
  • 49
  • 67
SeaWarrior404
  • 3,811
  • 14
  • 43
  • 65
  • What if you feed it with 1 - 2 - 2 - 3 - 1 - 2 - 2 - 3? What should be the output? – trincot Feb 16 '22 at 09:09
  • @trincot The idea is to get only unique elements here. So in the above case, the output should be -> 1 2 3 (Only unique elements, ordering does not matter) – SeaWarrior404 Feb 16 '22 at 09:29
  • Does the link that Ivar points to solve your problem? – trincot Feb 16 '22 at 09:31
  • Is there any requirement of delay between calls? Like if you have 1-2-3-4-5-6 in fast succession, should then all 6 calls be made with delay-time between two successive calls? That would not be "debouncing", but delaying excution for potentially a very long cumulative time... Or should some be skipped like is the default behaviour? Or should the delay be 0 after the first delay? – trincot Feb 16 '22 at 09:41
  • @trincot No matter how many calls are made..every call is guaranteed to return quickly. The expectation is just to get unique values no matter how many times each value is returned. – SeaWarrior404 Feb 16 '22 at 10:03
  • So actually the delay is not relevant here then? – trincot Feb 16 '22 at 10:07

1 Answers1

1

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.

trincot
  • 317,000
  • 35
  • 244
  • 286