Slide 1

Slide 1 text

JavaScript: repetita iuvant Luciano Mammino @loige

Slide 2

Slide 2 text

👋 Hello, I am Luciano Senior architect nodejsdesignpatterns.com Let’s connect: 🌎 loige.co 🐦 @loige 🧳 lucianomammino 20% OFF eBook on Packt.com 20NODEMAY

Slide 3

Slide 3 text

We are business focused technologists that deliver. Accelerated Serverless | AI as a Service | Platform Modernisation

Slide 4

Slide 4 text

👇 Get the slides (and click around…) loige.link/devcast2 @loige

Slide 5

Slide 5 text

How many ways do you know to do iteration in JavaScript? AFTERNOON TRIVIA 🤨 @loige

Slide 6

Slide 6 text

I counted 28! 😱 ● for i / for...in / for...of ● while / do while ● Array.forEach / Array.map / Array.flatMap / Array.reduce / Array.reduceRight / Array.filter / Array.find / Array.findIndex / Array.entries / Array.values / Array.every / Array.some ● Object.keys / Object.values / Object.entries @loige ● Iterators / Generators ● Spread operator ● Events ● Streams ● Async iterators / Async Generators ● for await...of

Slide 7

Slide 7 text

Agenda ● Syntax review ● Iteration protocols ○ Iterator protocol ○ Iterable protocol ○ Generator functions ○ Async iterator protocol ○ Async iterable protocol @loige

Slide 8

Slide 8 text

Syntax review for...of / spread operator / for await...of @loige

Slide 9

Slide 9 text

const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } for...of (with arrays) @loige Output Driulis Gonzalez Morales Ilias Iliadis Tadahiro Nomura Anton Geesink Teddy Riner Ryoko Tani

Slide 10

Slide 10 text

const judoka = 'Ryoko Tani' for (const char of judoka) { console.log(char) } for...of (with strings) @loige Output R y o k o T a n i

Slide 11

Slide 11 text

const medals = new Set([ 'gold', 'silver', 'bronze' ]) for (const medal of medals) { console.log(medal) } for...of (with Set) @loige Output gold silver bronze

Slide 12

Slide 12 text

const medallists = new Map([ ['Teddy Riner', 33], ['Driulis Gonzalez Morales', 16], ['Ryoko Tani', 16], ['Ilias Iliadis', 15] ]) for (const [judoka, medals] of medallists) { console.log(`${judoka} has won ${medals} medals`) } for...of (with Map) @loige Output Teddy Riner has won 33 medals Driulis Gonzalez Morales has won 16 medals Ryoko Tani has won 16 medals Ilias Iliadis has won 15 medals

Slide 13

Slide 13 text

const medallists = { 'Teddy Riner': 33, 'Driulis Gonzalez Morales': 16, 'Ryoko Tani': 16, 'Ilias Iliadis': 15 } for (const [judoka, medals] of Object.entries(medallists)) { console.log(`${judoka} has won ${medals} medals`) } for...of (with objects & Object.entries) @loige Output Teddy Riner has won 33 medals Driulis Gonzalez Morales has won 16 medals Ryoko Tani has won 16 medals Ilias Iliadis has won 15 medals

Slide 14

Slide 14 text

const medallists = { 'Teddy Riner': 33, 'Driulis Gonzalez Morales': 16, 'Ryoko Tani': 16, 'Ilias Iliadis': 15 } for (const [judoka, medals] of medallists) { console.log(`${judoka} has won ${medals} medals`) } for...of (with object literals) @loige ERROR! for (const [judoka, medals] of medallists) { ^ TypeError: medallists is not iterable at Object. (.../05-for-of-object.js:8:32)

Slide 15

Slide 15 text

const countdown = [3, 2, 1, 0] // spread into array const from5to0 = [5, 4, ...countdown] console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] // spread function arguments console.log('countdown data:', ...countdown) // countdown data: 3 2 1 0 Spread operator @loige

Slide 16

Slide 16 text

import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' const client = new DynamoDBClient({}); for await (const page of paginateListTables({ client }, {})) { // page.TableNames is an array of table names for (const tableName of page.TableNames) { console.log(tableName) } } for await...of (async iterable) @loige

Slide 17

Slide 17 text

Iteration protocols @loige

Slide 18

Slide 18 text

Why are iteration protocols important? ● Unified/interoperable approach to iteration ○ Use for...of, for await...of and spread operator ● You can create your own custom iterators/iterables ● Sequential iteration made easy (both sync and async) @loige

Slide 19

Slide 19 text

Iterator protocol In JavaScript, an object is an iterator if it has a next() method. Every time you call it, it returns an object with the keys done (boolean) and value. @loige

Slide 20

Slide 20 text

function createCountdown (from) { let nextVal = from return { next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } Countdown iterator @loige const countdown = createCountdown(3) console.log(countdown.next()) // { done: false, value: 3 } console.log(countdown.next()) // { done: false, value: 2 } console.log(countdown.next()) // { done: false, value: 1 } console.log(countdown.next()) // { done: false, value: 0 } console.log(countdown.next()) // { done: true }

Slide 21

Slide 21 text

Iterable protocol An object is iterable if it implements the @@iterator* method, a zero-argument function that returns an iterator. * Symbol.iterator @loige

Slide 22

Slide 22 text

function createCountdown (from) { let nextVal = from return { [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } Countdown iterable @loige const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0

Slide 23

Slide 23 text

Can an object be both an iterator and an iterable? 😎 @loige

Slide 24

Slide 24 text

const iterableIterator = { next() { return { done: false, value: "hello" } }, [Symbol.iterator]() { return this } } YES! 🤩 @loige iterableIterator.next() // { done: false, value: "hello" } for (const value of iterableIterator) { console.log(value) } // hello // hello // hello // ...

Slide 25

Slide 25 text

A generator function “produces” an object that is both an iterator and an iterable! 🤯 @loige Generators

Slide 26

Slide 26 text

function * createCountdown (from) { for (let i = from; i >= 0; i--) { yield i } } Using generator functions @loige // As iterator const countdown = createCountdown(3) console.log(countdown.next()) // { done: false, value: 3 } console.log(countdown.next()) // { done: false, value: 2 } console.log(countdown.next()) // { done: false, value: 1 } console.log(countdown.next()) // { done: false, value: 0 } console.log(countdown.next()) // { done: true } // As iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0

Slide 27

Slide 27 text

Well what about async iteration? 🤨

Slide 28

Slide 28 text

Async Iterator protocol An object is an async iterator if it has a next() method. Every time you call it, it returns a promise that resolves to an object with the keys done (boolean) and value. @loige

Slide 29

Slide 29 text

import { setTimeout } from 'timers/promises' function createAsyncCountdown (from, delay = 1000) { let nextVal = from return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } Countdown Async iterator @loige const countdown = createAsyncCountdown(3) console.log(await countdown.next()) // { done: false, value: 3 } console.log(await countdown.next()) // { done: false, value: 2 } console.log(await countdown.next()) // { done: false, value: 1 } console.log(await countdown.next()) // { done: false, value: 0 } console.log(await countdown.next()) // { done: true }

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Async Iterable protocol An object is an async iterable if it implements the @@asyncIterator* method, a zero-argument function that returns an async iterator. * Symbol.asyncIterator @loige

Slide 32

Slide 32 text

Countdown Async iterable import { setTimeout } from 'timers/promises' function createAsyncCountdown (from, delay = 1000) { return { [Symbol.asyncIterator]: async function () { return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 }

Slide 33

Slide 33 text

Countdown Async iterator/iterable with generators! import { setTimeout } from 'timers/promises' async function * createAsyncCountdown (from, delay = 1000) { for (let i = from; i >= 0; i--) { await setTimeout(delay) yield i } } @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 }

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

When to use async iterators ● Sequential iteration pattern ● Data arriving in order over time ● You need to complete processing the current “chunk” before you can request the next one ● Example: paginated iteration! @loige

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Want to learn more? ● nodejsdesignpatterns.com - possibly a great book 😇 ● nodejsdesignpatterns.com/blog/javascript-async-iterators/ - In-depth article on all things iterators ● loige.link/async-it - Finding a lost song with Node.js & async iterators @loige

Slide 38

Slide 38 text

Thank you! loige.link/devcast2 @loige 20% OFF eBook on Packt.com 20NODEMAY