JavaScript Iterators

The New Opening

Tomasz Ducin  •  ducin.dev  •  Bottega IT Minds

say "YIELD"!

Hi, I'm Tomasz

tomasz (at) ducin.dev

🦋 @ducin.dev

𝕏  @tomasz_ducin

Independent Consultant & Software Architect

Trainer, Speaker, Frontend & Backend

Bottega IT Minds, ArchitekturaNaFroncie.pl (ANF)

Warsaw, PL

array.map(fn)

array.values().map(fn)

.values()

const items = ['a', 'b', 'c']

function *map(iterable, mapperFn){
    for (item of iterable){
        const newItem = mapperFn(item)
        yield newItem
    }
}

const uppercasedIterator = 
  map(items, str => str.toUpperCase())

Iterators 101

// LAZY
const uppercased = map(items, str => str.toUpperCase())
uppercased.next() // {value: 'A', done: false}
uppercased.next() // {value: 'B', done: false}
uppercased.next() // {value: 'C', done: false}
uppercased.next() // {value: undefined, done: true}

// EAGER
const uppercased = map(items, str => str.toUpperCase())
[...uppercased] // ['A', 'B', 'C']

Evaluation: LAZY vs EAGER

what's the issue with arrays? 🤨

arrays - snapshots

iterators - pull-based streams

iterators - pull-based streams

iter.next()

iter.next()

iter.next()

iterators - pull-based streams

DAD JOKE TIME

array.map(fn)

array.values().map(fn)

.values()

laziness is economical

browser vs server

benchmarks 🥸

array ops vs iterator ops

🚀 test #1

📦 small data set: array(50)

🔨 no operations

👉 ~400 ops (iter) vs ~400 ops (arr)

VERDICT: no clear winner, results are NON reproducible

🚀 test #2

📦 small data set: array(50)

🔨 4 x map (trivial op)

👉 330k ops (iter) vs ~4k ops (arr)

VERDICT: iterators 99% times faster

🚀 test #3

📦 bigger data set: array(500)

🔨 4 x map (trivial op)

👉 ~300k ops (iter) vs ~400 ops (arr)

VERDICT: iterators 100% times faster

🚀 test #4

📦 super small data set: array(5)

🔨 4 x map (trivial op)

👉 ~275k ops (iter) vs ~4k ops (arr)

VERDICT: iterators 98% times faster

🚀 SANITY CHECK: iterators only

📦 bigger data set: array(500)

🔨 1*map vs 2*map vs 4*map vs 8*map

👉 ~475k ops (1) vs ~350k ops (2) vs ~225k ops (4) vs ~150k ops (8)

🚀 SANITY CHECK: iterators only

📦 bigger data set: array(500)

🔨 1*map vs 2*map vs 4*map vs 8*map

👉 ~475k ops (1) vs ~350k ops (2) vs ~225k ops (4) vs ~150k ops (8)

🚀 SANITY CHECK: iterators only

📦 bigger data set: array(500)

🔨 1*map vs 2*map vs 4*map vs 8*map

👉 ~475k ops (1) vs ~350k ops (2) vs ~225k ops (4) vs ~150k ops (8)

🚀 SANITY CHECK: iterators only

📦 bigger data set: array(500)

🔨 1*map vs 2*map vs 4*map vs 8*map

👉 ~475k ops (1) vs ~350k ops (2) vs ~225k ops (4) vs ~150k ops (8)

VERDICT: 1*map < 2*map < 4*map < 8*map
(less ops => faster, no sh__ Sherlock)

benchmarks 😉

my benchmark is more benchmarkish than your benchmark

what's the issue with iterators? 🤨

const items = ['a', 'b', 'c']

function *map(iterable, mapperFn){
    for (item of iterable){
        const newItem = mapperFn(item)
        yield newItem
    }
}

const uppercasedIterator = 
  map(items, str => str.toUpperCase())

verbosity...

iterator helpers, stage 4

https://github.com/tc39/proposal-iterator-helpers

reflect the well-known API
to a new powerful primitive

array.values() -> ArrayIterator
set.values()   -> SetIterator
map.keys()     -> MapIterator
map.values()   -> MapIterator
etc...

even
Object.keys(OBJ).values() -> ArrayIterator

Common API

for various data structures

Object.groupBy(array)

array.map(fn)

array.values().map(fn)

.values()

Thank you

Tomasz Ducin  •  ducin.dev

JavaScript Iterators

By Tomasz Ducin

JavaScript Iterators

  • 302