[Weekly Js Perf] Fastest way to initialize a Map with initial values
Tags: javascript, webdev, performance, programming
Published: 2023-03-18 17:02:00

**Welcome to Weekly JavaScript Performance, Here we explore weekly JavaScript-related performance tips and tricks so that you write better and faster apps!**

## The topic today: Performance of initializing Maps, and what the best method is to do so.

When working with bulk amounts of data it's important to initialize and use the data in the right way to ensure a fast and effective method of work.

We compare the following situations:
Item Initialization: 1, 100, 10000 **from an Object**. It's important to keep in mind that the way, you store your data also has a big impact.

Setup Code:
```js
// Set the number of iterations
const sampleSize = 1

// object to store the samples
const samples = {};

for (let i = 0; i < sampleSize; i++) {
  samples[crypto.randomUUID()] = crypto.randomUUID();
}
```

Benchmark 1 (Initializing in constructor):
```js
// Get an array of the keys in the samples object
const keys = Object.keys(samples)

// Create an empty array to store the key-value pairs as two-element arrays [Required by Map]
const initial = []
for (let i = 0; i<keys.length;i++) {
	initial.push([keys[i], samples[keys[i]]])
}
// initial schema: [key, value][]
const map = new Map(initial)
```

Benchmark 2 (Initializing in constructor via Object.entries):
```js
new Map(Object.entries(samples))
```

Benchmark 3 (Initializing it via Map.set):
```js 
// Get an array of the keys in the samples object
const keys = Object.keys(samples)
// create a new empty Map
const map = new Map()
for (let i = 0; i<keys.length;i++) {
    // assign properties via set
	map.set(keys[i], samples[keys[i]])
}
```

So now how is the performance?
<u>sampleSize: 1</u>
Benchmark 1: 25812739 ops / S (33.83% slower) ±1.99%
Benchmark 2: 10358422 ops / S (73.4% slower) ±1.32%
Benchmark 3: 39010393 ops / S (fastest) ±1.57%
<u>sampleSize: 100</u>
Benchmark 1: 197028   ops / S (18.51% slower) ±2.21%
Benchmark 2: 74668    ops / S (69.13% slower) ±1.69% _nice²_
Benchmark 3: 39010393 ops / S (fastest) ±1.36%
<u>sampleSize: 10_000</u>
Benchmark 1: 680 ops / S (18.51% slower) ±15.66%
Benchmark 1: 419 ops / S (51.6% slower) ±1.19%
Benchmark 3: 812 ops / S (fastest) ±12.13%

**So what do we learn from this?**
Method 1 Requires us to create additional arrays so we can store them in the required Schema: `[key, value][]` is slower. 
Method 2 Makes the step in Method 1 automatically but is much slower, but extremely consistent. 
Method 3 is the fastest and recommended Method.
[Jsbench Link to Benchmark](https://jsbench.me/irlfe5fydi/1)

**_But what If the Data is already prepared in the correct schema?_**

**Setup Code:**
```js
// Set the number of iterations
const iterations = 1

// object to store the samples
const samples = {};

for (let i = 0; i < iterations; i++) {
  samples[crypto.randomUUID()] = crypto.randomUUID();
}

// Get an array of the keys in the samples object
const keys = Object.keys(samples)

// Create an empty array to store the key-value pairs as two-element arrays [Required by Map]
const initial = []
for (let i = 0; i<keys.length;i++) {
	initial.push([keys[i], samples[keys[i]]])
}
```

Benchmark 1 & 2 (Initializing in constructor):
```js
const map = new Map(initial)
```

Benchmark 3 (Initializing it via Map.set):
```js 
const map = new Map()
for (let i = 0; i<keys.length;i++) {
	map.set(keys[i], samples[keys[i]])
}
```

**So now how is the performance when the Data is prepared?**
<u>sampleSize: 1</u>
Benchmark 1: 43308604 ops / S (8.19% slower) ±1.69% _nice_
Benchmark 3: 47173798 ops / S (fastest) ±1.57%
<u>sampleSize: 100</u>
Benchmark 1: 424558 ops / S (fastest) ±2.07%
Benchmark 3: 399689 ops / S (5.86% slower) ±1.43%
<u>sampleSize: 10_000</u>
Benchmark 1: 2213 ops / S (fastest) ±1.83%
Benchmark 3: 2037 ops / S (7.98 % slower) ±0.73%

This is surprising! If we have more than 1 entry to set _(2 is already 11% slower)_, then using the entries method is always faster!
[Jsbench Link to Benchmark](https://jsbench.me/9clfe7n4ck/1)


**Conclusion:**
If you have the entries already perfectly set up, then I recommend you to use the initializer to set up your Map.
But if you have it in any other form (even if you can choose how you want to save the Data) I strongly recommend you to use From our First test the Benchmark 3 Method (via Object.keys then for loop). The reason why it's usually slower is that when we use functions like Object.entries, they tend to create a lot of arrays that only hold key, value data. So If you for example have to load a JSON to convert them to Maps, It's much better to store them as an Object and then use the Method described Above. (Also it will cost you much less Memory, all of those arrays take a lot of Memory!)

**TLTR:** Use set in every case (including the way to save and load the Data) with object.keys to create the Maps, unless you need the Data in a format like Object.entries()

_Keep in mind that results may vary from browser to browser, tests have been conducted with Chrome, run the benchmarks yourself! (Results may vary depending on CPU Too, on intel Firefox, object.entries is faster (by 5% on 10k))_