Do browsers(etc) **internally optimize** their retrieval of javascript object properties? - javascript

Additional Note:
I did check this previous answer and desire an answer that is more current and that is less Chrome specific: Performance of key lookup in JavaScript object
Assuming a standard javascript “dictionary” object with properties like this:
var myObject = {
Key1: ”Value1”,
Key2: ”Value2”,
Key3: ”Value3”,
…
Key500: ”Value500”
}
Does anyone know if browsers(etc) internally optimize their retrieval of these properties?
A good case might be auto-sort + binary search.
A not-so-good case might be simple linear search.
EcmaScript standards say the browsers can do the internals as they wish:
[browsers,etc] may support [object’s] internal properties with any
implementation-dependent behaviour as long as it is consistent with
the specific host object restrictions stated in this document.
and
The mechanics and order of enumerating the properties … is not
specified.
I'm not really needing to know a specific optimization, I just want to know if they are trying to optimize beyond a simple linear search.
So, does anyone have "inside" knowledge?

It depends on the browser and the JavaScript engine. Google's V8 dynamically creates hidden classes instead of dynamic lookup, to reduce the time used to access properties. Using hidden classes also has the added benefit of using class-based optimizations such as inline caching.
There is more information here under the "Fast Property Access" section. The idea basically comes from this paper: An Efficient Implementation of Self, a Dynamically-Typed Object-Oriented Language Based on Prototypes.
Internet Explorer has a "fast type system" to optimize property access. More details in this presentation.
Mozilla's SpiderMonkey engine uses a property cache (warning: the details are somewhat obsolete, but it basically still uses a property cache).
The new IonMonkey engine uses inline property-caches, but details seem to be scant so far.

Yes. The specification does not require such optimications, as you have already noted, but it can be observed empirically. I tested how quickly keys are grabbed from objects that contain up to 500,000 elements. (test here, be warned that it will freeze your browser for a little while).
The key retrieval time does not increase with the size of the object, which means that it has O(1) time complexity for search.

Related

Why is getting from Map slower than getting from object?

I'm considering migrating my state management layer to using Map versus using a standard object.
From what I've read, Map is effectively a hash table whereas Objects use hidden classes under the hood. Generally it's advised, where the properties are likely to be dynamically added or removed it's more efficient to use Map.
I set up a little test and to my surprise accessing values in the Object version was faster.
https://jsfiddle.net/mfbx9da4/rk4hocwa/20/
The article also mentions fast and slow properties. Perhaps the reason my code sample in test1 is so fast is because it is using fast properties? This seems unlikely as the object has 100,000 keys. How can I tell if the object is using fast properties or dictionary lookup? Why would the Map version be slower?
And yes, in practice, looks like a premature optimization, root of all evil ... etc etc. However, I'm interested in the internals and curious to know of best practices of choosing Map over Object.
(V8 developer here.)
Beware of microbenchmarks, they are often misleading.
V8's object system is implemented the way it is because in many cases it turns out to be very fast -- as you can see here.
The primary reason why we recommend using Map for map-like use cases is because of non-local performance effects that the object system can exhibit when certain parts of the machinery get "overloaded". In a small test like the one you have created, you won't see this effect, because nothing else is going on. In a large app (using many objects with many properties in many different usage patterns), it's still not guaranteed (because it depends on what the rest of the app is doing) but there's a good chance that using Maps where appropriate will improve overall performance -- if the overall system previously happened to run into one of the unfortunate situations.
Another reason is that Maps handle deletion of entries much better than Objects do, because that's a use case their implementation explicitly anticipates as common.
That said, as you already noted, worrying about such details in the abstract is a case of premature optimization. If you have a performance problem, then profile your app to figure out where most time is being spent, and then focus on improving those areas. If you do end up suspecting that the use of objects-as-maps is causing issues, then I recommend to change the implementation in the app itself, and measure (with the real app!) whether it makes a difference.
(See here for a related, similarly misleading microbenchmark, where even the microbenchmark itself started producing opposite results after minor modifications: Why "Map" manipulation is much slower than "Object" in JavaScript (v8) for integer keys?. That's why we recommend benchmarking with real apps, not with simplistic miniature scenarios.)

JavaScript: performance constraints of `delete` keyword

I'm trying to better learn how JS works under the hood and I've heard in the past that the delete keyword (specifically node.js or browsers using V8) results in poor performance, so I want to see if I can figure out what the benefits/detriments are for using that keyword.
I believe the reasoning for not using delete is that removing a property leads to a rebuilding of hidden class transitions and thus a recompiling of the inline cache. However, I believe it is also true that the object prototype will no longer enumerate that property, so if the object is used heavily the upfront cost may eventually pay off.
So:
Are my assumptions about the tradeoffs correct?
If they are correct, is one factor more important than the other (e.g. is rebuilding the IC much more expensive than many prototype enumerations)?
V8 developer here. Short answer: "it depends".
Having an unused property doesn't hurt; there is no general "enumeration cost" unless you actually perform explicit enumerations. In other words, an "enumeration cost" only exists if you find yourself doing something like this:
for (var p in object) {
if (p === old_property_that_I_could_have_deleted) continue;
/* process other properties... */
}
The key reason why it's hard to give a concrete answer (or to provide a canonical example where an effect would be measurable) is because the effects are non-local: they depend both on what exactly you're doing with the object in question, and on what the rest of your app is doing. Deleting a property from one object may well cause operations on other objects to become slower. Or faster. It depends.
To take a step back and look at the high-level situation: JavaScript as a language sort of assumes that objects are represented as dictionaries. Deleting an entry in a dictionary should be perfectly fine, which is why it makes sense that the delete operator exists. In practice, it turns out that an engine can achieve huge performance improvements for read-heavy apps, which is by far the most common case, if it does not store objects as dictionaries, but instead more like something that resembles C/C++ structs. However, such an object representation is (1) generally hard/inefficient to do when properties get deleted, and (2) the engine may well interpret even the first deletion of a property as a hint that the programmer wants this particular object to behave like a dictionary, so it might switch the internal representation over. If a fast-to-modify dictionary is what you wanted, then that's fine (it will provide a benefit even); however if you wanted the object to remain in slow-to-modify/fast-to-read mode, you would perceive the transition to fast-to-modify/slow-to-read dictionary mode as a performance problem.
Thankfully there is a great solution nowadays: when you want a dictionary, use a Map or Set. Engines can (and usually will) assume that you'll want to delete entries from these, so the implementations are optimized for making that possible without negative side effects; in particular no hidden classes are involved.
A few remarks on your assumptions: deleting a property makes an object (mostly) leave the system of hidden class transitions, no transitions will be rebuilt. There is no single global "inline cache", there are many inline caches sprinkled all over your functions. They don't get rebuilt, they just transition to slower and slower modes the more different cases they have to handle. (That's generally how caching works: caching a single case provides huge speedups; on the other end of the scale if you have as many different cases as executions, then a cache just wastes time and memory without providing any benefit.) Again the effect of dictionary-mode objects depends on the overall situation: an inline cache dealing with (mostly) dictionary-mode objects typically exhibits performance somewhere in between (1) an inline cache that only has to deal with objects sharing the single same hidden class, and (2) an inline cache that has to deal with hundreds or thousands of different hidden classes.

how are javascript properties added to and looked up on objects?

When adding properties to a JavaScript object are they added in an ordered way (alphabetical etc). And if so does that mean when you lookup a property on a JavaScript object that a quick algorithm is used like a binary tree search? I did a search for this and just found lots of explanations for prototype inheritance which I already understand I'm just interested in how a property is looked up within a single level of the prototype chain.
That entirely depends on the implementation. Google's V8 engine probably does it differently than Firefox's JagerMonkey. And they almost certainly does it different than IE6. Looking up a property in an object is just an interface (a fairly common Map interface as programmers would call it). The only thing Javascript guarantees you is the methods of the interface, no details about implementation, and that's a good thing. It could be a hash table (probably) or it could be a linked list (less likely, but possible) or it could even be a binary search tree.
The point is that we don't know how it's implemented, nor should we. And you should make no assumptions about the implementation. As is common with abstraction in programming, just assume it's magic. :)
Here is a high level description of how v8 does it using hidden classes it then looks up the property value by using the fixed offset provided by the definition of the hidden class. It also confirms that most other implementations use a dictionary type data object.

Performance of key lookup in JavaScript object

I just read this question: are there dictionaries in javascript like python?
One of the answers said that you can use JavaScript objects like Python dictionaries. Is that true? What is the performance of a key lookup in an object? Is it O(1)? Is adding a key to the object also constant time (hashing)?
The V8 design docs imply lookups will be at least this fast, if not faster:
Most JavaScript engines use a dictionary-like data structure as
storage for object properties - each property access requires a
dynamic lookup to resolve the property's location in memory. This
approach makes accessing properties in JavaScript typically much
slower than accessing instance variables in programming languages like
Java and Smalltalk. In these languages, instance variables are located
at fixed offsets determined by the compiler due to the fixed object
layout defined by the object's class. Access is simply a matter of a
memory load or store, often requiring only a single instruction.
To reduce the time required to access JavaScript properties, V8 does
not use dynamic lookup to access properties. Instead, V8 dynamically
creates hidden classes behind the scenes. [...] In V8, an object changes
its hidden class when a new property is added.
It sounds like adding a new key might be slightly slower, though, due to the hidden class creation.
Yes, you can assume that adding a key, and later using it for access are effectively constant time operations.
Under the hood the JS engine may apply some techniques to optimize subsequent lookups, but for the purposes of any algorithm, you can assume O(1).
Take a look at a similar question How does JavaScript VM implements Object property access? and the answer. Here I described the optimization technique used by JS engines and how it affects the key lookup performance. I hope these details help you write more efficient JS code.

What is Javascript missing?

Javascript is an incredible language and libraries like jQuery make it almost too easy to use.
What should the original designers of Javascript have included in the language, or what should we be pressuring them into adding to future versions?
Things I'd like to see:-
Some kind of compiled version of the language, so we programmers can catch more of our errors earlier, as well as providing a faster solution for browsers to consume.
optional strict types (eg, being able to declare a var as a float and keep it that way).
I am no expert on Javascript, so maybe these already exist, but what else should be there? Are there any killer features of other programming languages that you would love to see?
Read Javascript: The Good Parts from the author of JSLint, Douglas Crockford. It's really impressive, and covers the bad parts too.
One thing I've always longed for and ached for is some support for hashing. Specifically, let me track metadata about an object without needing to add an expando property on that object.
Java provides Object.getHashCode() which, by default, uses the underlying memory address; Python provides id(obj) to get the memory address and hash(obj) to be customizable; etc. Javascript provides nothing for either.
For example, I'm writing a Javascript library that tries to unobtrusively and gracefully enhance some objects you give me (e.g. your <li> elements, or even something unrelated to the DOM). Let's say I need to process each object exactly once. So after I've processed each object, I need a way to "mark it" as seen.
Ideally, I could make my own hashtable or set (either way, implemented as a dictionary) to keep track:
var processed = {};
function process(obj) {
var key = obj.getHashCode();
if (processed[key]) {
return; // already seen
}
// process the object...
processed[key] = true;
}
But since that's not an option, I have to resort to adding a property onto each object:
var SEEN_PROP = "__seen__";
function process(obj) {
if (obj[SEEN_PROP]) { // or simply obj.__seen__
return; // already seen
}
// process the object...
obj[SEEN_PROP] = true; // or obj.__seen__ = true
}
But these objects aren't mine, so this makes my script obtrusive. The technique is effectively a hack to work around the fact that I can't get a reliable hash key for any arbitrary object.
Another workaround is to create wrapper objects for everything, but often you need a way to go from the original object to the wrapper object, which requires an expando property on the original object anyway. Plus, that creates a circular reference which causes memory leaks in IE if the original object is a DOM element, so this isn't a safe cross-browser technique.
For developers of Javascript libraries, this is a recurring issue.
What should the original designers of Javascript have included in the language, or what should we be pressuring them into adding to future versions?
They should have got together and decided together what to implement, rather than competing against each other with slightly different implementations of the language (naming no names), to prevent the immense headache that has ensued for every developer over the past 15 years.
The ability to use arrays/objects as keys without string coercion might've been nice.
Javascript is missing a name that differentiates it from a language it is nothing like.
There are a few little things it could do better.
Choice of + for string concatenation was a mistake. An & would have been better.
It can be frustrating that for( x in list ) iterates over indices, as it makes it difficult to use a literal array. Newer versions have a solution.
Proper scoping would be nice. v1.7 is adding this, but it looks clunky.
The way to do 'private' and 'protected' variables in an object is a little bit obscure and hard to remember as it takes advantage of closures and how they affect scoping. Some syntactic sugar to hide the mechanics of this would be fabulous.
To be honest, many of the problems I routinely trip over are actually DOM quirks, not JavaScript per se. The other big problem, of course, is that recent versions of JavaScript have interesting and useful things, like generators. Unfortunately, most browsers are stuck at 1.5. Apparantly only FireFox is forging ahead.
File IO is missing.... though some would say it doesn't really need it...

Categories

Resources