📱 Erkannter Endgerättyp ⛱️ Tag und Nacht. Verbraucht keinen oder einen 🍪. 🖼️ Hintergrund ändern. Verbraucht keinen oder einen 🍪.
🧬 0 Ihre DNS in den Krei.se-DNS-Servern, führt zum Bio-Labor 🍪 0 Anzahl Ihrer gespeicherten Kekse, führt zur Keksdose       

🍥 Was sind die schnellsten Loops in 🪩 TypeScript?

Sooo, nach 3 Tagen Benchmarken und Browser-Wechsel, etc. gibt es eine Lösung die für alle Browser optimal ist und mit 2 Regeln auskommt:

Objects → for...in

Wer seine Typen selbst definiert oder Record<T,T> nutzt wird sich keine prototypes ins Haus holen. Man erhält Key und Value. Noch schneller geht es mit Map<T,T> statt Records

Arrays → for

Man erhält Index und Value - Key gibt es in Arrays ohnehin nicht.

Das wars. Higher-order-functions on arrays machen den Speed nie, wer Array.map() fährt holt sich mind. 10 bis 20x Geschwindigkeitsverlust ins Haus. Das ist total idiotisch. Das Problem ist ja nichtmal dass es mal eben bis zu 50x langsamer ist, das potenziert sich ja ohne Probleme in Frameworks.

Brave und Firefox haben unterschiedliche Werte für Object.keys/values/entries, aber in jedem Fall ist for ... in die schnellste Lösung.

Ich lasse den Beitrag trotzdem so stehen. Wer typsicher und threadsafe schreibt und vom Clienten holt wozu er fähig ist bekommt mittlerweile mit TS und Esbuild Möglichkeit nahezu an der Hardware Code zu schicken - das fetzt schon.

AirBNB Style decisions

Airbnb style guide wird einem erklären, man möge keine Iteratoren verwenden, da sie den state des Objektes ändern (tun Sie überhaupt nicht), aber ehrlichgesagt sind die higher-order-functions trotzdem mit overhead verbunden und wirklich lesbar ist das auch nicht.

Object.prototype

Das benutzt sowieso keine ernstzunehmende Library - systemweit den prototypen zu ergänzen ist völlig unnötig und wenn man das wirklich braucht kann man es mit .enumerable = false auch aus for ... in raushalten.

Benchmarks

Ich finde bei den Benchmarks mega interessant, dass Firefox an sich viel schneller ist - meine Usecases geben das aber nicht immer her, ThreeJS oder 2D-Canvas sind in Chrome doch irgendwie fixer. Es liegt wohl am besseren Multi-Threading in Chrome, d.h. wer selbst die Threads holt dürfte seine Page auf FF und Chrome gleichermaßen fix zum Kunden bekommen.

Wer sauberen Code schreibt und for-loops nutzt, seine Typen klar deklariert ist mit Firefox wahrscheinlich besser dran.

Das ist eigentlich ganz schön so, denn ehrlichgesagt kann man sich Chrome wirklich nur für den Speed ins Haus holen.

Brave

Esbuild TS -> JS. Results are for 1 Million Cells, 100000 Links

Swarm[CellType] Tests:

Object.keys(): 117.90ms
Object.values(): 219.10ms
Object.entries(): 265.00ms
Object.entries().forEach with key,value and index: 276.70ms
for...in: 114.70ms                      

Array Tests:

array for loop: 5.80ms                  
array for...of: 122.10ms
array forEach: 81.70ms
array for...in: 496.50ms
array Object.entries(): 1188.70ms        <--- wtf, 200x times slower
array map(): 127.50ms                   <--- airbnb style will slow your page!!!

Records vs Map Tests:

obj[key] Lookup: 1544 ms
map.get(key) Lookup: 97 ms

FF

Esbuild TS -> JS. Results are for 1 Million Cells, 100000 Links

Swarm[CellType] Tests:

Object.keys(): 41 ms
Object.values(): 12 ms
Object.entries(): 36 ms
Object.entries().forEach with key,value and index: 42 ms
for...in: 32 ms                     <-- for 1 million cells btw.
for...in counted: 36 ms
for...of .entries(): 46 ms

Array Tests:

array for loop: 7 ms                <-- means you can easily loop 250000 links at 60fps
array for...of: 64 ms
array forEach: 54 ms
array for...in: 887 ms              <--- why FF is slower usually, never use for ... in on Arrays!
array Object.entries(): 840 ms      <--- wtf, 200x times slower
array map(): 111 ms

Records vs Map Tests:

obj[key] Lookup: 5531 ms
map.get(key) Lookup: 116 ms 

Cheat Sheet Decision Finder

TLDR: Use Map<T,T> and Array<T> only lol

Data Structure Recommended
Array of objects (T[]) forEach, for-of, map
Object as dictionary (Record) Object.entries(obj) + for-of
Object that needs array-like behavior Add [Symbol.iterator]
Fastest method for performance-sensitive tasks Classic for loop

Cheat Sheet Speed

keyed Record<string, T> Fastest: for
Construct Example How Index Key Value Use Case
for in for (const key in obj) enumerate properties, numeric ordered, string insertion order, symbol keys are ignored ✅ (obj[key]) Fast ⚠️ includes prototype properties
for of for (const value of obj) expects iterator to enumerate property-values Fast ⚠️ includes prototype properties
.forEach Keys Object.keys(obj).forEach(key => { ... }) These all will return you another object which maps index, keys and values. ↪️ (derived) ✅ (obj[key]) Safe, avoids prototype properties
.forEach Values Object.values(obj).forEach(value => { ... }) ↪️ (derived) Safe, values only
.forEach Keys+Values+Indizes Object.entries(obj).forEach(([key, value], index) => { ... }) ↪️ (derived) Safe
for of .entries for (const [key, value] of Object.entries(obj)) 🚫 in some styles "Clean and readable"
indexed Array<T> Fastest: for
Construct Example how Index Key Value Use Case
for for(let i = 0; i < arr.length; i++) ✅ Yes (arr[i]) Fastest, manual index handling
for of for (const value of arr) uses iterator of object Readable, avoids index
for in for (const index of arr) this will turn your index into strings ✅ (arr[parseFloat(index)]) Don't use that, Slow as f... (10%)
.forEach arr.forEach((value, index) => { ... }) Callback-based, readable, fast
.map, .reduce, .filter, etc. arr.map(value => value * 2) higher-order callbacks ✅ (Returns new array) surprisingly slow 65%
.entries arr.entries() + for (const [index, value] of arr.entries()) Best for index & value