0

I'm using a library () that exposes a function clone() that is called recursively for all the nodes in a hierarchy.

If I monkey patch the function to execute some additional code, this will be executed multiple times.

Instead, I need to execute my code at the end of the whole recursive calls, but I can't find a way to do it.

pc.Entity.prototype.clone = function() {
    ... some code
    // then for each child it calls itself
}

If I try this way I get "my stuff" executed multiple times.

pc.Entity.prototype.cloneOriginal = pc.Entity.prototype.clone;

pc.Entity.prototype.clone = function() {
    var c = this.cloneOriginal();
    // do my stuff
    return c;
}

I need to "override" the clone method so that after all its recursive calls, I can execute my code.

trincot
  • 317,000
  • 35
  • 244
  • 286
mcmorry
  • 132
  • 1
  • 7

2 Answers2

2

I'd still go with a simple flag to determine wether I'm inside a recursion or not.

//no need to store that function on the prototype itself
const cloneOriginal = pc.Entity.prototype.clone;

let inRecursion = false;
pc.Entity.prototype.clone = function() {
    //just pass through the call to the original function.
    if(inRecursion)
        return cloneOriginal.call(this);

    inRecursion = true;
    var c = cloneOriginal.call(this);
    inRecursion = false;

    // do my stuff
    return c;
}

inRecursion is a flag, specific for this single implementation. Maybe you want to wrap this code in a block or an iife to ensure that the variables are not accessible from outside of your clone-method.


could you point me to some more info about the optimization you are speaking about. What should I google?

You'll find most about v8 optimizations on google, but most modern browsers do similar stuff. I just googled and came across this article Performance Tips for JavaScript in V8. It's a bit older, but I think it's a good point to start getting an understanding on the kind of optimizations that JS engines do to your code to make it faster.

But as the article it mentions, don't loose yourself in (pointless) optimizations.

Thomas
  • 11,958
  • 1
  • 14
  • 23
2

You can achieve that by temporarily restoring the original function before launching it. And when it is finished, you set your trap again, and perform your post processing:

const orig_clone = pc.Entity.prototype.clone; // Save original clone
// Set trap:
pc.Entity.prototype.clone = function patched_clone(...args) {
    pc.Entity.prototype.clone = orig_clone; // Restore original function
    let result = this.clone(...args); // Execute it
    // All is done, including recursion. 
    pc.Entity.prototype.clone = patched_clone; // Set trap again
    // Your code comes here
    console.log('post processing');
    return result;
}
trincot
  • 317,000
  • 35
  • 244
  • 286
  • let result = this.clone() would be the same? – mcmorry Feb 10 '18 at 20:08
  • Doesn't this change the hidden class for all instances of Entity, every time you call this function? And if it does, doesn't this basically throw all optimizations for all codes that deal with an instance of Entity out the window? As these objects should look like a new type to the optimizer, every time you call `anyEntity.clone()`. – Thomas Feb 10 '18 at 21:10
  • Yes it does, @Thomas. If the intention was to only do that for one `entity` object, then of course one would use `entity.clone` instead of `pc.Entity.prototype.clone`. But the OP did not specify anything about this, and their code was hinting it had to be applied to the prototype, not one specific instance. – trincot Feb 10 '18 at 21:12
  • @Thomas could you point me to some more info about the optimization you are speaking about. What should I google? – mcmorry Feb 11 '18 at 11:14