Storing document and window references in an object to get better performance

229 views Asked by At

I have one question and don't know do I do right thing.

I define window and document in objects or global variable in my pluins like this:

var myplugin = {
     document : document || {},
     window : window || {}
};

After I call that when I need like this:

myplugin.window.location.href = 'http://flyflyflymachine.etc';

And I would like to know do I get some better performance or is unnecessarily?

3

There are 3 answers

0
traktor On BEST ANSWER

In theory this kind of nano-optimization is more appplicable to nested functions created when a plugin is defined in terms of an IIFE instead of using an object literal initializer.

When code references a variable of object, the javascript engine has to search the current lexical scope record first, followed by any parent lexical scrope records until the variable or object definition is either found or proven not to have been defined.

Lexical scope records are created for for loops using let variable definitions and for functions to hold arguments and variables. So in a deeply nested for loop, in a deeply nested function, there could be a number of scope records to inspect before finding either window or document.

Making a copy of a global or outer function reference could reduce the number of scope records to search. A net performance gain will only arise if the overhead of making the copy is less than the overhead of the JavaSript engine searching the intermediary scope records, multiplied by the number of times the outer reference is used. This may be both rare in practice and difficult to prove if the gain is small.

The kind of plugin definition in the post, consisting of an "Object object" intializer instead of an IIFE does not meet the criteria of speeding up object reference searching and, indeed, could actually slow things down.

3
DRAB On

You seem to be concerned about window or document not existing. If, for example, this code were run from inside a Worker or NodeJS script, it would throw an error.

So you could "optimize" this in two ways:

Use a namespace with the this keyword (from global scope, this will refer to the global object)

var myPlugin = {};
(function myPluginNS(_global) {
  myPlugin.window = _global;
  myPlugin.document = _global.document || {};
})(this);

Use good ol' fashioned try-catch

var myPlugin = {};
try {
  myPlugin.window = window;
} catch (e) {
  myPlugin.window = {};
}
try {
  myPlugin.document = document;
} catch (e) {
  myPlugin.document = {};
}

Admittedly, not really an "optimization", but it will at least ensure your code can run in various JS run-times.

2
Casper Beyer On

As for performance, yes caching can help but you are not caching anything here. Merely replacing one lookup with another one (yourplugin.document vs window.document).

Actually in that case, just document is faster, but unless you are in a tight loop calling it a few thousand times, don't bother with these kind of nano optimisations.