If you already have a subscription, you can sign in.
Enjoy free content straight from your inbox 💌
00:00
The word weak in JavaScript implies that a data structure will only hold a weak reference to an object, and this allows that reference object to be garbage collected. Even if we still have the data structure in scope. To understand the weak map, we need to understand one critical issue with the map class, we create a simple instance of the map and four, two variables X and Y. We create two simple objects and use these objects as keys within a map to store two simple string values. Now, ideally when these objects go out of scope or we stop referencing them, for example, by assigning X and Y to null,
00:35
they should be available for garbage collection. However, there is an issue that the map still holds a reference to the keys that we used and we can actually get those original objects simply by iterating over the map keys. So since our code still has a path to get those original objects, they cannot be garbage collected. And the main thing preventing the garbage collection of those original objects is the fact that a map has a strong reference to its keys. This is the main difference between a map and a weak map. So let's create those X and Y objects. Again,
01:08
create a new weak map and we can use it just like we were using the map. We can use these X and Y objects to store values against them and we can get those values back by using the weak map get method. However, the map itself doesn't hold a strong reference to the past. In keys, a strong reference is what we have when we assign an object to a variable using the equal sign. This is not what the weak map does internally. It uses something more low level. The only strong references to those original objects right now exist as the variables X and Y. So if we actually assign X and Y to null,
01:42
there is nothing within R code or within WeakMap that is directly equal to those objects. What this means is that the garbage collector can jump in and free up the memory for X and Y and any of the values that were associated with these keys. Obviously, WeakMap is a very specialized version of the map class and therefore the WeakMap comes with significant limitations when compared to a map. The first limitation is that the keys for a weak map must be an object. It has to be something that a garbage collector can garbage collect. So let's create two simple objects assigned to variables, alpha and omega.
02:17
To demonstrate the features of the weak map, we can actually pass an retriable of entries just like we can do with the map to the weak map constructor. Here. The map has a single key, which is the alpha object with the value, which is the alpha string. We can set a value against an object as well if you wanted to. So for Omega, we set the value to be the omega string. We can get a value back by passing in a correct object for the key, so we can get back that alpha string from the alpha object and we can also delete keys. For example, we can delete the key for the alpha object and the delete method will return true if the key existed. If we try to delete alpha again,
02:53
it no longer exists and therefore we get false. If we try to get the value for a key that no longer Exists within the map, for example, alpha no longer exists, we get back undefined, and we can also check if a key exists within the map with the has method. So alpha no longer exists, however Omeka still does beyond the restriction that the keys must be objects. All of these methods are exactly the same as the app within the map data structure. However, unlike the map, the weak map has no size property. It has no iteration methods to go through either the keys or the values or the entries,
03:27
and it has no clear method because it is not holding any strong reference to the keys it contains. Since you cannot iterate over the keys or get the keys from the map yourself, there is no point in cleaning it either. We've talked about it from a theoretical perspective, but let's do a practical demonstration of the fact that the standard map class blocks, keys, and therefore values from being garbage collected. Whereas a weak map doesn't because it only holds a weak reference to its keys. We create a simple utility called fill that will take a map like data structure and a given string character.
04:01
Then it'll iterate 2,500 times and each time set a new key within the map like data structure with the new object each time with an ID property, which we will calculate using math dot random. And for the value we will allocate a massive array consisting of a hundred thousand items all filled with the same character. The objective of the fill method is to fill up a map with lots of new objects created using math dot random, with values pointing to giant arrays consisting of characters. Let's do a simple test to compare the memory performance of the map and the week
04:35
map classes. And for this, we will utilize the memory used and the collect garbage utilities, which we created in our previous session on JavaScript memory management and garbage collection. First up, let's put the standard map class to the test by creating an instance of the map, noting down the current memory that is being used, fill that map up with the chili character note on the memory being used afterwards and then try to collect the garbage. Those objects that we created within the fill function are not being referenced anywhere within the code over here, but they are still being referenced by the map. This means that the garbage collector will not be able to do anything,
05:10
and in fact if we just run it again with a different character, the memory consumption with the standard map will just go up and up because all of those objects exist as keys that we can get access to using the default map before we run this code. Let's do the same thing with the weak map. We create an instance of the weak map and then note on the memory used, fill up the weak map with a different character note on the memory used afterwards, collect the garbage, and we can do that as many times as we want. What will happen is that because those keys only existed within the fill function and they are not referenced from anywhere within our code,
05:47
they only exist as weak references internally within the JavaScript built in weak map. This means that they're available for garbage collection and the garbage collector will free up that Memory for us because of the massive amount of content that we are creating. So now for the moment of truth, let's run this code and see it in action. With the map you can see that we start off with a low amount of memory, but after we fill it up, the memory just spikes through the roof. And even though we dry garbage collection, we cannot free any memory. That is because all of those objects we can still get access to using the map, and when we fill it up again,
06:21
the memory spikes again and we still cannot collect any garbage with the weak map. When we fill it up, the memory does go up. However, all of that memory can be garbage collected because nothing is holding a strong reference to those objects. Similarly, we fill it up again and the memory again goes up, but all of that memory can again be garbage collected. An obvious question you should have is what are the main use cases for using a weak map? The answer is pretty simple. When you want to associate data to an object and tie that data into the object lifecycle from a memory perspective,
06:54
so both the data and the object get garbage collected together, and you want to do this without polluting any of the object properties, you might want to use a weak map as an example. Consider this heavy competition that we need to do given an object that has a value member. The thing that makes it a heavy competition is the fact that we are looping a million times. Let's create a hundred simple objects with a value member initialized to the array index, and may year the time that it takes to do this heavy computation for all of these objects three different times. And of course this will all work perfectly fine,
07:28
but wouldn't it be great if we could associate the result of the heavy computation with the object so that we don't have to calculate it again and again, but do it in a manner that doesn't hold on to a strong reference for the object. So if the objects ever go out of scope, they can be easily copies collected along with any computation that we might have stored against him, and no surprise, that is exactly what the weak map is for. We create an instance of the weak map, create a function memorized heavy computation that takes an object, and if the object doesn't already exist within the weak map,
08:01
we do the heavy computation and set the result against this object as a key and then return the result. Otherwise, we already have that competition within the map and we can simply get that result back by using WeakMap dot get. So let's run through the scenario again, but this time by using a Memoed heavy competition, we look through the objects three times and each time calculate the Memoed heavy computation. The first time the competition will take place, but the second two times, we will simply be getting them back from the weak map that we created. So if you run this code,
08:34
you can see that the raw version takes around 1.2 seconds, whereas the weak map based memorized version is done in under half a second. Weak map is probably not something that you will be using unless you're building a framework, but if you ever run across it, you can be confident that this is now something that you already know. As always, thank you for joining me and I will see you in the next one.