JavaScript Iterators

The New Opening

Tomasz Ducin ย โ€ข ย ducin.dev

say "YIELD"!

Hi, I'm Tomasz

Independent Consultant & Softwareย Architect

Trainer, Speaker, JS/TS Expert

ArchitekturaNaFroncie.pl (ANF)

Warsaw, PL

tomasz (at) ducin.dev

๐Ÿฆ‹ @ducin.dev

๐• ย @tomasz_ducin

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