Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reiterating JavaScript & Node.js iterators

Reiterating JavaScript & Node.js iterators

In this talk we will revisit the iteration protocols offered by JavaScript (iterable, iterator, async iterable and async iterator). We will explore generators and async generators as well. We will use this opportunity to discuss some interesting applications of these patterns in Node.js and we will compare them with more traditional approaches like Event Emitters and Node.js Streams. Finally, we will discuss some interesting integrations between traditional approaches and iterators and show some patterns and anti-patterns.

F3a6662b3cd161c3c2f13604965ed0f2?s=128

Luciano Mammino

June 16, 2021
Tweet

Transcript

  1. Reiterating JavaScript & Node.js iterators Luciano Mammino ( ) @loige

    loige.link/iter RomaJS - June 16, 2021 1
  2. @loige loige.link/iter 2

  3. How many ways do you know to "do iteration" in

    JavaScript & Node.js? 😰 @loige 3
  4. for i / for...in / for...of @loige 4

  5. while / do while @loige 5

  6. Array.forEach / Array.map / Array.flatMap / Array.reduce / Array.reduceRight /

    Array.filter / Array.find / Array.findIndex / Array.entries / Array.values / Array.every / Array.some @loige 6
  7. Object.keys / Object.values / Object.entries @loige 7

  8. Iterators / Generators @loige 8

  9. Spread operator [...iterable] @loige 9

  10. Events / Streams @loige 10

  11. Async iterators / Async generators @loige 11

  12. for await...of @loige 12

  13. That was 28 different concepts! 😳 @loige 13

  14. 📝 AGENDA Iteration protocols... What? Why? Syntax review Iteration protocols

    Iterator protocol Iterable protocol Generator functions Async iterator protocol Async iterable protocol Tips & tricks @loige 14
  15. Let me introduce myself... @loige 15

  16. Let me introduce myself... I'm Luciano ( 🍕🍝) 👋 @loige

    15
  17. Let me introduce myself... I'm Luciano ( 🍕🍝) 👋 Senior

    Architect @loige 15
  18. Let me introduce myself... I'm Luciano ( 🍕🍝) 👋 Senior

    Architect nodejsdp.link Co-Author of Node.js Design Patterns 👉 @loige 15
  19. Let me introduce myself... I'm Luciano ( 🍕🍝) 👋 Senior

    Architect nodejsdp.link Co-Author of Node.js Design Patterns 👉 Connect with me: (blog) (twitter) (twitch) (github) loige.co @loige loige lmammino @loige 15
  20. We are business focused technologists that deliver. | | Accelerated

    Serverless AI as a Service Platform Modernisation WE ARE HIRING: Do you want to ? work with us @loige 16
  21. Iteration protocols what? why? 🤔 @loige An attempt at standardizing

    "iteration" behaviors providing a consistent and interoperable API Use for...of, for await...of and spread operator. You can also create lazy iterators You can also deal with async iteration You can create your own custom iterators/iterables 17
  22. Syntax Review 🧐 @loige 18

  23. const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro

    Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 @loige for...of 19
  24. const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro

    Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] 1 2 3 4 5 6 7 8 9 for (const judoka of judokas) { 10 console.log(judoka) 11 } 12 @loige for...of Driulis Gonzalez Morales Ilias Iliadis Tadahiro Nomura Anton Geesink Teddy Riner Ryoko Tani OUTPUT 19
  25. const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro

    Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] 1 2 3 4 5 6 7 8 9 for (const judoka of judokas) { 10 console.log(judoka) 11 } 12 for (const judoka of judokas) { } const judokas = [ 1 'Driulis Gonzalez Morales', 2 'Ilias Iliadis', 3 'Tadahiro Nomura', 4 'Anton Geesink', 5 'Teddy Riner', 6 'Ryoko Tani' 7 ] 8 9 10 console.log(judoka) 11 12 @loige for...of Driulis Gonzalez Morales Ilias Iliadis Tadahiro Nomura Anton Geesink Teddy Riner Ryoko Tani OUTPUT 19
  26. const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro

    Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] 1 2 3 4 5 6 7 8 9 for (const judoka of judokas) { 10 console.log(judoka) 11 } 12 for (const judoka of judokas) { } const judokas = [ 1 'Driulis Gonzalez Morales', 2 'Ilias Iliadis', 3 'Tadahiro Nomura', 4 'Anton Geesink', 5 'Teddy Riner', 6 'Ryoko Tani' 7 ] 8 9 10 console.log(judoka) 11 12 console.log(judoka) const judokas = [ 1 'Driulis Gonzalez Morales', 2 'Ilias Iliadis', 3 'Tadahiro Nomura', 4 'Anton Geesink', 5 'Teddy Riner', 6 'Ryoko Tani' 7 ] 8 9 for (const judoka of judokas) { 10 11 } 12 @loige for...of Driulis Gonzalez Morales Ilias Iliadis Tadahiro Nomura Anton Geesink Teddy Riner Ryoko Tani OUTPUT 19
  27. const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro

    Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] 1 2 3 4 5 6 7 8 9 for (const judoka of judokas) { 10 console.log(judoka) 11 } 12 for (const judoka of judokas) { } const judokas = [ 1 'Driulis Gonzalez Morales', 2 'Ilias Iliadis', 3 'Tadahiro Nomura', 4 'Anton Geesink', 5 'Teddy Riner', 6 'Ryoko Tani' 7 ] 8 9 10 console.log(judoka) 11 12 console.log(judoka) const judokas = [ 1 'Driulis Gonzalez Morales', 2 'Ilias Iliadis', 3 'Tadahiro Nomura', 4 'Anton Geesink', 5 'Teddy Riner', 6 'Ryoko Tani' 7 ] 8 9 for (const judoka of judokas) { 10 11 } 12 const judokas = [ 'Driulis Gonzalez Morales', 'Ilias Iliadis', 'Tadahiro Nomura', 'Anton Geesink', 'Teddy Riner', 'Ryoko Tani' ] for (const judoka of judokas) { console.log(judoka) } 1 2 3 4 5 6 7 8 9 10 11 12 @loige for...of Driulis Gonzalez Morales Ilias Iliadis Tadahiro Nomura Anton Geesink Teddy Riner Ryoko Tani OUTPUT 19
  28. const judoka = 'Ryoko Tani' for (const char of judoka)

    { console.log(char) } 1 2 3 4 5 @loige for...of (with strings) 20
  29. const judoka = 'Ryoko Tani' for (const char of judoka)

    { console.log(char) } 1 2 3 4 5 @loige for...of (with strings) R y o k o T a n i OUTPUT 20
  30. const medals = new Set([ 'gold', 'silver', 'bronze' ]) for

    (const medal of medals) { console.log(medal) } 1 2 3 4 5 6 7 8 9 @loige for...of (with Set) 21
  31. const medals = new Set([ 'gold', 'silver', 'bronze' ]) for

    (const medal of medals) { console.log(medal) } 1 2 3 4 5 6 7 8 9 @loige for...of (with Set) gold silver bronze OUTPUT 21
  32. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with Map) 22
  33. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with Map) 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 OUTPUT 22
  34. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with object & Object.entries) 23
  35. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with object & Object.entries) 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 OUTPUT 23
  36. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with object literals) 24
  37. 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`) } 1 2 3 4 5 6 7 8 9 10 @loige for...of (with object literals) for (const [judoka, medals] of medallists) { ^ TypeError: medallists is not iterable at Object. (.../05-for-of-object.js:8:32) ERROR 24
  38. 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 1 2 3 4 5 6 7 8 9 @loige Spread operator 25
  39. 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 1 2 3 4 5 6 7 8 9 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 @loige Spread operator 25
  40. 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 1 2 3 4 5 6 7 8 9 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 // spread into array const from5to0 = [5, 4, ...countdown] console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] const countdown = [3, 2, 1, 0] 1 2 3 4 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 @loige Spread operator 25
  41. 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 1 2 3 4 5 6 7 8 9 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 // spread into array const from5to0 = [5, 4, ...countdown] console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] const countdown = [3, 2, 1, 0] 1 2 3 4 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 // spread function arguments console.log('countdown data:', ...countdown) // countdown data: 3 2 1 0 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 7 8 9 @loige Spread operator 25
  42. 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 1 2 3 4 5 6 7 8 9 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 // spread into array const from5to0 = [5, 4, ...countdown] console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] const countdown = [3, 2, 1, 0] 1 2 3 4 5 6 // spread function arguments 7 console.log('countdown data:', ...countdown) 8 // countdown data: 3 2 1 0 9 // spread function arguments console.log('countdown data:', ...countdown) // countdown data: 3 2 1 0 const countdown = [3, 2, 1, 0] 1 2 // spread into array 3 const from5to0 = [5, 4, ...countdown] 4 console.log(from5to0) // [ 5, 4, 3, 2, 1, 0 ] 5 6 7 8 9 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 1 2 3 4 5 6 7 8 9 @loige Spread operator 25
  43. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige for await...of (async iterable) 26
  44. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' 1 2 3 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 @loige for await...of (async iterable) 26
  45. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' 1 2 3 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 const client = new DynamoDBClient({}); import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 @loige for await...of (async iterable) 26
  46. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' 1 2 3 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 const client = new DynamoDBClient({}); import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 for await (const page of paginateListTables({ client }, {})) { } import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 const client = new DynamoDBClient({}); 6 7 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 13 @loige for await...of (async iterable) 26
  47. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' 1 2 3 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 const client = new DynamoDBClient({}); import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 for await (const page of paginateListTables({ client }, {})) { } import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 const client = new DynamoDBClient({}); 6 7 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 13 // page.TableNames is an array of table names for (const tableName of page.TableNames) { console.log(tableName) } import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 9 10 11 12 } 13 @loige for await...of (async iterable) 26
  48. 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import { DynamoDBClient, paginateListTables } from '@aws-sdk/client-dynamodb' 1 2 3 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 const client = new DynamoDBClient({}); import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 6 7 for await (const page of paginateListTables({ client }, {})) { 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 } 13 for await (const page of paginateListTables({ client }, {})) { } import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 const client = new DynamoDBClient({}); 6 7 8 // page.TableNames is an array of table names 9 for (const tableName of page.TableNames) { 10 console.log(tableName) 11 } 12 13 // page.TableNames is an array of table names for (const tableName of page.TableNames) { console.log(tableName) } import { 1 DynamoDBClient, 2 paginateListTables 3 } from '@aws-sdk/client-dynamodb' 4 5 const client = new DynamoDBClient({}); 6 7 for await (const page of paginateListTables({ client }, {})) { 8 9 10 11 12 } 13 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) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige for await...of (async iterable) 26
  49. Iteration Protocols 😵 💫 @loige 27

  50. 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 28
  51. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige Countdown iterator 29
  52. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 @loige Countdown 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 } 29
  53. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 @loige Countdown 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 } 29
  54. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { } function createCountdown (start) { 1 let nextVal = start 2 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 13 } 14 @loige Countdown 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 } 29
  55. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { } function createCountdown (start) { 1 let nextVal = start 2 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 13 } 14 next () { } function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 12 } 13 } 14 @loige Countdown 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 } 29
  56. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { } function createCountdown (start) { 1 let nextVal = start 2 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 13 } 14 next () { } function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 12 } 13 } 14 if (nextVal < 0) { return { done: true } } function createCountdown (start) { 1 let nextVal = start 2 return { 3 next () { 4 5 6 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 @loige Countdown 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 } 29
  57. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { } function createCountdown (start) { 1 let nextVal = start 2 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 13 } 14 next () { } function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 12 } 13 } 14 if (nextVal < 0) { return { done: true } } function createCountdown (start) { 1 let nextVal = start 2 return { 3 next () { 4 5 6 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { done: false, value: nextVal-- } function createCountdown (start) { 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 8 9 10 11 } 12 } 13 } 14 @loige Countdown 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 } 29
  58. function createCountdown (start) { let nextVal = start return {

    next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 14 let nextVal = start function createCountdown (start) { 1 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { } function createCountdown (start) { 1 let nextVal = start 2 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 13 } 14 next () { } function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 12 } 13 } 14 if (nextVal < 0) { return { done: true } } function createCountdown (start) { 1 let nextVal = start 2 return { 3 next () { 4 5 6 7 return { 8 done: false, 9 value: nextVal-- 10 } 11 } 12 } 13 } 14 return { done: false, value: nextVal-- } function createCountdown (start) { 1 let nextVal = start 2 return { 3 next () { 4 if (nextVal < 0) { 5 return { done: true } 6 } 7 8 9 10 11 } 12 } 13 } 14 function createCountdown (start) { let nextVal = start return { next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige Countdown 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 } 29
  59. Iterable protocol An object is iterable if it implements the

    @@iterator* method, a zero-argument function that returns an iterator. * Symbol.iterator @loige 30
  60. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @loige Countdown iterable 31
  61. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  62. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 let nextVal = start function createCountdown (start) { 1 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 } 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  63. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 let nextVal = start function createCountdown (start) { 1 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 } 16 return { } function createCountdown (start) { 1 let nextVal = start 2 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 15 } 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  64. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 let nextVal = start function createCountdown (start) { 1 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 } 16 return { } function createCountdown (start) { 1 let nextVal = start 2 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 15 } 16 [Symbol.iterator]: () => ({ }) function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 14 } 15 } 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  65. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 let nextVal = start function createCountdown (start) { 1 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 } 16 return { } function createCountdown (start) { 1 let nextVal = start 2 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 15 } 16 [Symbol.iterator]: () => ({ }) function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 14 } 15 } 16 next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } function createCountdown (start) { 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 5 6 7 8 9 10 11 12 13 }) 14 } 15 } 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  66. function createCountdown (start) { let nextVal = start return {

    [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function createCountdown (start) { } 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 16 let nextVal = start function createCountdown (start) { 1 2 return { 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 } 15 } 16 return { } function createCountdown (start) { 1 let nextVal = start 2 3 [Symbol.iterator]: () => ({ 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 }) 14 15 } 16 [Symbol.iterator]: () => ({ }) function createCountdown (start) { 1 let nextVal = start 2 return { 3 4 next () { 5 if (nextVal < 0) { 6 return { done: true } 7 } 8 return { 9 done: false, 10 value: nextVal-- 11 } 12 } 13 14 } 15 } 16 next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } function createCountdown (start) { 1 let nextVal = start 2 return { 3 [Symbol.iterator]: () => ({ 4 5 6 7 8 9 10 11 12 13 }) 14 } 15 } 16 function createCountdown (start) { let nextVal = start return { [Symbol.iterator]: () => ({ next () { if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } }) } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @loige Countdown iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 31
  67. Can an object be both an iterator and an iterable?!

    🤨 @loige 32
  68. const iterableIterator = { next() { return { done: false,

    value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 @loige Iterator + Iterable 33
  69. const iterableIterator = { next() { return { done: false,

    value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 const iterableIterator = { } 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 [Symbol.iterator]() { 5 return this 6 } 7 8 @loige Iterator + Iterable iterableIterator.next() // { done: false, value: "hello" } for (const value of iterableIterator) { console.log(value) } // hello // hello // hello // ... 33
  70. const iterableIterator = { next() { return { done: false,

    value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 const iterableIterator = { } 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 [Symbol.iterator]() { 5 return this 6 } 7 8 next() { return { done: false, value: "hello" } }, const iterableIterator = { 1 2 3 4 [Symbol.iterator]() { 5 return this 6 } 7 } 8 @loige Iterator + Iterable iterableIterator.next() // { done: false, value: "hello" } for (const value of iterableIterator) { console.log(value) } // hello // hello // hello // ... 33
  71. const iterableIterator = { next() { return { done: false,

    value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 const iterableIterator = { } 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 [Symbol.iterator]() { 5 return this 6 } 7 8 next() { return { done: false, value: "hello" } }, const iterableIterator = { 1 2 3 4 [Symbol.iterator]() { 5 return this 6 } 7 } 8 [Symbol.iterator]() { return this } const iterableIterator = { 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 5 6 7 } 8 @loige Iterator + Iterable iterableIterator.next() // { done: false, value: "hello" } for (const value of iterableIterator) { console.log(value) } // hello // hello // hello // ... 33
  72. const iterableIterator = { next() { return { done: false,

    value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 const iterableIterator = { } 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 [Symbol.iterator]() { 5 return this 6 } 7 8 next() { return { done: false, value: "hello" } }, const iterableIterator = { 1 2 3 4 [Symbol.iterator]() { 5 return this 6 } 7 } 8 [Symbol.iterator]() { return this } const iterableIterator = { 1 next() { 2 return { done: false, value: "hello" } 3 }, 4 5 6 7 } 8 const iterableIterator = { next() { return { done: false, value: "hello" } }, [Symbol.iterator]() { return this } } 1 2 3 4 5 6 7 8 @loige Iterator + Iterable iterableIterator.next() // { done: false, value: "hello" } for (const value of iterableIterator) { console.log(value) } // hello // hello // hello // ... 33
  73. Generators A generator function "produces" an object that is both

    an iterator and an iterable! 🤯 @loige 34
  74. function * createCountdown (start) { for (let i = start;

    i >= 0; i--) { yield i } } 1 2 3 4 5 @loige 35
  75. function * createCountdown (start) { for (let i = start;

    i >= 0; i--) { yield i } } 1 2 3 4 5 function * createCountdown (start) { } 1 for (let i = start; i >= 0; i--) { 2 yield i 3 } 4 5 @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 } 35
  76. function * createCountdown (start) { for (let i = start;

    i >= 0; i--) { yield i } } 1 2 3 4 5 function * createCountdown (start) { } 1 for (let i = start; i >= 0; i--) { 2 yield i 3 } 4 5 for (let i = start; i >= 0; i--) { } function * createCountdown (start) { 1 2 yield i 3 4 } 5 @loige // As iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 // 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 } 35
  77. function * createCountdown (start) { for (let i = start;

    i >= 0; i--) { yield i } } 1 2 3 4 5 function * createCountdown (start) { } 1 for (let i = start; i >= 0; i--) { 2 yield i 3 } 4 5 for (let i = start; i >= 0; i--) { } function * createCountdown (start) { 1 2 yield i 3 4 } 5 yield i function * createCountdown (start) { 1 for (let i = start; i >= 0; i--) { 2 3 } 4 } 5 @loige // As iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 // 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 } 35
  78. function * createCountdown (start) { for (let i = start;

    i >= 0; i--) { yield i } } 1 2 3 4 5 function * createCountdown (start) { } 1 for (let i = start; i >= 0; i--) { 2 yield i 3 } 4 5 for (let i = start; i >= 0; i--) { } function * createCountdown (start) { 1 2 yield i 3 4 } 5 yield i function * createCountdown (start) { 1 for (let i = start; i >= 0; i--) { 2 3 } 4 } 5 function * createCountdown (start) { for (let i = start; i >= 0; i--) { yield i } } 1 2 3 4 5 @loige // As iterable const countdown = createCountdown(3) for (const value of countdown) { console.log(value) } // 3 // 2 // 1 // 0 // 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 } 35
  79. Well, what about async iteration? @loige 36

  80. 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 37
  81. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige 38
  82. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 @loige 38
  83. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 @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 } 38
  84. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 @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 } 38
  85. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 13 } 14 @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 } 38
  86. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 13 } 14 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 12 } 13 } 14 @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 } 38
  87. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 13 } 14 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 12 } 13 } 14 await setTimeout(delay) import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 @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 } 38
  88. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 13 } 14 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 12 } 13 } 14 await setTimeout(delay) import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 8 9 10 11 } 12 } 13 } 14 @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 } 38
  89. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 14 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 return { 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 5 async next () { 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 13 } 14 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 6 await setTimeout(delay) 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 12 } 13 } 14 await setTimeout(delay) import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 7 if (nextVal < 0) { 8 return { done: true } 9 } 10 return { done: false, value: nextVal-- } 11 } 12 } 13 } 14 if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 let nextVal = start 4 return { 5 async next () { 6 await setTimeout(delay) 7 8 9 10 11 } 12 } 13 } 14 import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay = 1000) { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @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 } 38
  90. @loige 39

  91. 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 40
  92. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @loige 41
  93. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 @loige 41
  94. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  95. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  96. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  97. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  98. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 15 } 16 } 17 } 18 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 14 } 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  99. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 15 } 16 } 17 } 18 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 14 } 15 } 16 } 17 } 18 await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 9 10 11 12 13 } 14 } 15 } 16 } 17 } 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  100. import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay

    = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 17 } 18 return { import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 [Symbol.asyncIterator]: function () { return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 5 let nextVal = start 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 13 } 14 } 15 } 16 } 17 } 18 let nextVal = start import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 6 return { 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 } 15 } 16 } 17 } 18 return { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 7 async next () { 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 } 14 15 } 16 } 17 } 18 async next () { } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 8 await setTimeout(delay) 9 if (nextVal < 0) { 10 return { done: true } 11 } 12 return { done: false, value: nextVal-- } 13 14 } 15 } 16 } 17 } 18 await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } import { setTimeout } from 'timers/promises' 1 2 function createAsyncCountdown (start, delay = 1000) { 3 return { 4 [Symbol.asyncIterator]: function () { 5 let nextVal = start 6 return { 7 async next () { 8 9 10 11 12 13 } 14 } 15 } 16 } 17 } 18 import { setTimeout } from 'timers/promises' function createAsyncCountdown (start, delay = 1000) { return { [Symbol.asyncIterator]: function () { let nextVal = start return { async next () { await setTimeout(delay) if (nextVal < 0) { return { done: true } } return { done: false, value: nextVal-- } } } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 41
  101. import { setTimeout } from 'timers/promises' async function * createAsyncCountdown

    (start, delay = 1000) { for (let i = start; i >= 0; i--) { await setTimeout(delay) yield i } } 1 2 3 4 5 6 7 8 @loige 42
  102. import { setTimeout } from 'timers/promises' async function * createAsyncCountdown

    (start, delay = 1000) { for (let i = start; i >= 0; i--) { await setTimeout(delay) yield i } } 1 2 3 4 5 6 7 8 async function * createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 for (let i = start; i >= 0; i--) { 4 await setTimeout(delay) 5 yield i 6 } 7 8 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 42
  103. import { setTimeout } from 'timers/promises' async function * createAsyncCountdown

    (start, delay = 1000) { for (let i = start; i >= 0; i--) { await setTimeout(delay) yield i } } 1 2 3 4 5 6 7 8 async function * createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 for (let i = start; i >= 0; i--) { 4 await setTimeout(delay) 5 yield i 6 } 7 8 await setTimeout(delay) yield i import { setTimeout } from 'timers/promises' 1 2 async function * createAsyncCountdown (start, delay = 1000) { 3 for (let i = start; i >= 0; i--) { 4 5 6 } 7 } 8 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 42
  104. import { setTimeout } from 'timers/promises' async function * createAsyncCountdown

    (start, delay = 1000) { for (let i = start; i >= 0; i--) { await setTimeout(delay) yield i } } 1 2 3 4 5 6 7 8 async function * createAsyncCountdown (start, delay = 1000) { } import { setTimeout } from 'timers/promises' 1 2 3 for (let i = start; i >= 0; i--) { 4 await setTimeout(delay) 5 yield i 6 } 7 8 await setTimeout(delay) yield i import { setTimeout } from 'timers/promises' 1 2 async function * createAsyncCountdown (start, delay = 1000) { 3 for (let i = start; i >= 0; i--) { 4 5 6 } 7 } 8 import { setTimeout } from 'timers/promises' async function * createAsyncCountdown (start, delay = 1000) { for (let i = start; i >= 0; i--) { await setTimeout(delay) yield i } } 1 2 3 4 5 6 7 8 @loige const countdown = createAsyncCountdown(3) for await (const value of countdown) { console.log(value) // 3 ... 2 ... 1 ... 0 } 42
  105. @loige 43

  106. When to use async iterators @loige Sequential iteration pattern Data

    arriving in order over time You need to complete processing the current “chunk” before you can request the next one Examples paginated iteration consuming tasks from a remote queue 44
  107. Tips & pitfalls ☠ @loige 45

  108. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 @loige Node.js readable streams are async iterators 46
  109. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 @loige Node.js readable streams are async iterators 46
  110. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 @loige Node.js readable streams are async iterators 46
  111. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 let bytes = 0 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 @loige Node.js readable streams are async iterators 46
  112. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 let bytes = 0 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 6 bytes += chunk.length 7 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 @loige Node.js readable streams are async iterators 46
  113. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 let bytes = 0 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 6 bytes += chunk.length 7 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 bytes += chunk.length import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 @loige Node.js readable streams are async iterators 46
  114. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 let bytes = 0 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 6 bytes += chunk.length 7 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 bytes += chunk.length import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 console.log(`bigdata.csv: ${bytes} bytes`) import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 10 @loige Node.js readable streams are async iterators 46
  115. import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv')

    let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 2 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 let bytes = 0 import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 6 bytes += chunk.length 7 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 bytes += chunk.length import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 7 } 8 9 console.log(`bigdata.csv: ${bytes} bytes`) 10 console.log(`bigdata.csv: ${bytes} bytes`) import { createReadStream } from 'fs' 1 2 const sourceStream = createReadStream('bigdata.csv') 3 4 let bytes = 0 5 for await (const chunk of sourceStream) { 6 bytes += chunk.length 7 } 8 9 10 import { createReadStream } from 'fs' const sourceStream = createReadStream('bigdata.csv') let bytes = 0 for await (const chunk of sourceStream) { bytes += chunk.length } console.log(`bigdata.csv: ${bytes} bytes`) 1 2 3 4 5 6 7 8 9 10 @loige Node.js readable streams are async iterators 46
  116. What about backpressure? 😩 @loige 47

  117. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige 48
  118. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 @loige 48
  119. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 @loige 48
  120. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 @loige 48
  121. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 @loige 48
  122. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 const canContinue = destStream.write(chunk) import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 @loige 48
  123. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 const canContinue = destStream.write(chunk) import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 if (!canContinue) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 13 } 14 @loige 48
  124. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 const canContinue = destStream.write(chunk) import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 if (!canContinue) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 13 } 14 // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 10 11 // ok now it's safe to resume writing 12 } 13 } 14 @loige 48
  125. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 const canContinue = destStream.write(chunk) import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 if (!canContinue) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 13 } 14 // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 10 11 // ok now it's safe to resume writing 12 } 13 } 14 // ok now it's safe to resume writing import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 12 } 13 } 14 @loige 48
  126. import { createReadStream } from 'fs' import { once }

    from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import { createReadStream } from 'fs' import { once } from 'events' 1 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const sourceStream = createReadStream('bigdata.csv') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 const destStream = new SlowTransform() import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 for await (const chunk of sourceStream) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 14 const canContinue = destStream.write(chunk) import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 } 13 } 14 if (!canContinue) { } import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 // ok now it's safe to resume writing 12 13 } 14 // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 10 11 // ok now it's safe to resume writing 12 } 13 } 14 // ok now it's safe to resume writing import { createReadStream } from 'fs' 1 import { once } from 'events' 2 3 const sourceStream = createReadStream('bigdata.csv') 4 const destStream = new SlowTransform() 5 6 for await (const chunk of sourceStream) { 7 const canContinue = destStream.write(chunk) 8 if (!canContinue) { 9 // backpressure, now we stop and we need to wait for drain 10 await once(destStream, 'drain') 11 12 } 13 } 14 import { createReadStream } from 'fs' import { once } from 'events' const sourceStream = createReadStream('bigdata.csv') const destStream = new SlowTransform() for await (const chunk of sourceStream) { const canContinue = destStream.write(chunk) if (!canContinue) { // backpressure, now we stop and we need to wait for drain await once(destStream, 'drain') // ok now it's safe to resume writing } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige 48
  127. But if you are dealing with streaming pipelines it's probably

    easier to use . pipeline() @loige 49
  128. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige 50
  129. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 @loige 50
  130. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 import { createReadStream, createWriteStream } from 'fs' import { createBrotliCompress } from 'zlib' import { pipeline } from 'stream/promises' 1 2 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 @loige 50
  131. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 import { createReadStream, createWriteStream } from 'fs' import { createBrotliCompress } from 'zlib' import { pipeline } from 'stream/promises' 1 2 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 5 6 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 @loige 50
  132. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 import { createReadStream, createWriteStream } from 'fs' import { createBrotliCompress } from 'zlib' import { pipeline } from 'stream/promises' 1 2 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 5 6 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 await pipeline( sourceStream, compress, destStream ) import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 9 10 11 12 13 @loige 50
  133. import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream

    } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 import { createReadStream, createWriteStream } from 'fs' import { createBrotliCompress } from 'zlib' import { pipeline } from 'stream/promises' 1 2 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 5 6 7 8 await pipeline( 9 sourceStream, 10 compress, 11 destStream 12 ) 13 await pipeline( sourceStream, compress, destStream ) import { pipeline } from 'stream/promises' 1 import { createReadStream, createWriteStream } from 'fs' 2 import { createBrotliCompress } from 'zlib' 3 4 const sourceStream = createReadStream('bigdata.csv') 5 const compress = createBrotliCompress() 6 const destStream = createWriteStream('bigdata.csv.br') 7 8 9 10 11 12 13 import { pipeline } from 'stream/promises' import { createReadStream, createWriteStream } from 'fs' import { createBrotliCompress } from 'zlib' const sourceStream = createReadStream('bigdata.csv') const compress = createBrotliCompress() const destStream = createWriteStream('bigdata.csv.br') await pipeline( sourceStream, compress, destStream ) 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige 50
  134. In Node.js we can convert any Event Emitter to an

    Async Iterator! 😱 @loige 51
  135. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 @loige 52
  136. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 @loige 52
  137. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 import glob from 'glob' // from npm import { on } from 'events' 1 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 @loige 52
  138. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 import glob from 'glob' // from npm import { on } from 'events' 1 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 const matcher = glob('**/*.js') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 @loige 52
  139. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 import glob from 'glob' // from npm import { on } from 'events' 1 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 const matcher = glob('**/*.js') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 for await (const [filePath] of on(matcher, 'match')) { } import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 6 console.log(filePath) 7 8 @loige 52
  140. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 import glob from 'glob' // from npm import { on } from 'events' 1 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 const matcher = glob('**/*.js') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 for await (const [filePath] of on(matcher, 'match')) { } import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 6 console.log(filePath) 7 8 console.log(filePath) import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 7 } 8 @loige 52
  141. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 import glob from 'glob' // from npm import { on } from 'events' 1 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 const matcher = glob('**/*.js') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 for await (const [filePath] of on(matcher, 'match')) { } import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 6 console.log(filePath) 7 8 console.log(filePath) import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 7 } 8 import { on } from 'events' import glob from 'glob' // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } 1 2 3 4 5 6 7 8 @loige 52
  142. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') 1 2 3 4 5 6 7 8 9 10 11 @loige 53
  143. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') 1 2 3 4 5 6 7 8 9 10 11 // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 9 10 11 @loige 53
  144. import { on } from 'events' import glob from 'glob'

    // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') 1 2 3 4 5 6 7 8 9 10 11 // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') import { on } from 'events' 1 import glob from 'glob' // from npm 2 3 const matcher = glob('**/*.js') 4 5 for await (const [filePath] of on(matcher, 'match')) { 6 console.log(filePath) 7 } 8 9 10 11 import { on } from 'events' import glob from 'glob' // from npm const matcher = glob('**/*.js') for await (const [filePath] of on(matcher, 'match')) { console.log(filePath) } // ⚠ DANGER, DANGER (high voltage ⚡ ): We'll never get here! console.log('ALL DONE! :)') 1 2 3 4 5 6 7 8 9 10 11 @loige 53
  145. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @loige 54
  146. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 @loige 54
  147. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 @loige 54
  148. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 try { } catch (err) { // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 @loige 54
  149. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 try { } catch (err) { // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 if (!ac.signal.aborted) { console.error(err) process.exit(1) } import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 14 15 16 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 @loige 54
  150. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 try { } catch (err) { // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 if (!ac.signal.aborted) { console.error(err) process.exit(1) } import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 14 15 16 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 @loige 54
  151. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 try { } catch (err) { // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 if (!ac.signal.aborted) { console.error(err) process.exit(1) } import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 14 15 16 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 21 @loige 54
  152. import { on } from 'events' import glob from 'glob'

    const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const ac = new global.AbortController() import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 matcher.once('end', () => ac.abort()) import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 try { } catch (err) { // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 if (!ac.signal.aborted) { console.error(err) process.exit(1) } import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 14 15 16 17 // we ignore the AbortError 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 // we ignore the AbortError import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 18 } 19 20 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 21 console.log('NOW WE GETTING HERE! :)') // YAY! 😻 import { on } from 'events' 1 import glob from 'glob' 2 3 const matcher = glob('**/*.js') 4 const ac = new global.AbortController() 5 6 matcher.once('end', () => ac.abort()) 7 8 try { 9 for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { 10 console.log(`./${filePath}`) 11 } 12 } catch (err) { 13 if (!ac.signal.aborted) { 14 console.error(err) 15 process.exit(1) 16 } 17 // we ignore the AbortError 18 } 19 20 21 import { on } from 'events' import glob from 'glob' const matcher = glob('**/*.js') const ac = new global.AbortController() matcher.once('end', () => ac.abort()) try { for await (const [filePath] of on(matcher, 'match', { signal: ac.signal })) { console.log(`./${filePath}`) } } catch (err) { if (!ac.signal.aborted) { console.error(err) process.exit(1) } // we ignore the AbortError } console.log('NOW WE GETTING HERE! :)') // YAY! 😻 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @loige 54
  153. NOTE: If you know ahead of time how many events

    you need to process you can also use a break in the for...await loop. @loige 55
  154. LAST TIP: Can we use async iterators to handle web

    requests a-la-Deno? 🦕 @loige 56
  155. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 @loige 57
  156. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 import { createServer } from 'http' import { on } from 'events' 1 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 @loige 57
  157. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 import { createServer } from 'http' import { on } from 'events' 1 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 const server = createServer() server.listen(8000) import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 @loige 57
  158. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 import { createServer } from 'http' import { on } from 'events' 1 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 const server = createServer() server.listen(8000) import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 for await (const [req, res] of on(server, 'request')) { } import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 7 res.end('hello dear friend') 8 9 @loige 57
  159. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 import { createServer } from 'http' import { on } from 'events' 1 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 const server = createServer() server.listen(8000) import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 for await (const [req, res] of on(server, 'request')) { } import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 7 res.end('hello dear friend') 8 9 res.end('hello dear friend') import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 8 } 9 @loige 57
  160. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 import { createServer } from 'http' import { on } from 'events' 1 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 const server = createServer() server.listen(8000) import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 5 6 for await (const [req, res] of on(server, 'request')) { 7 res.end('hello dear friend') 8 } 9 for await (const [req, res] of on(server, 'request')) { } import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 7 res.end('hello dear friend') 8 9 res.end('hello dear friend') import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 8 } 9 import { createServer } from 'http' import { on } from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 @loige 57
  161. EASY PEASY LEMON SQUEEZY! 🍋 But... wait, aren't we processing

    all requests in series, now? 😱 @loige 58
  162. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { // ... AS LONG AS WE DON'T USE await HERE, WE ARE FINE! } 1 2 3 4 5 6 7 8 9 @loige 59
  163. import { createServer } from 'http' import { on }

    from 'events' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { // ... AS LONG AS WE DON'T USE await HERE, WE ARE FINE! } 1 2 3 4 5 6 7 8 9 // ... AS LONG AS WE DON'T USE await HERE, WE ARE FINE! import { createServer } from 'http' 1 import { on } from 'events' 2 3 const server = createServer() 4 server.listen(8000) 5 6 for await (const [req, res] of on(server, 'request')) { 7 8 } 9 @loige 59
  164. import { createServer } from 'http' import { on }

    from 'events' import { setTimeout } from 'timers/promises' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { await setTimeout(1000) res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 10 11 @loige 60
  165. import { createServer } from 'http' import { on }

    from 'events' import { setTimeout } from 'timers/promises' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { await setTimeout(1000) res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 10 11 import { setTimeout } from 'timers/promises' import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 const server = createServer() 5 server.listen(8000) 6 7 for await (const [req, res] of on(server, 'request')) { 8 await setTimeout(1000) 9 res.end('hello dear friend') 10 } 11 @loige 60
  166. import { createServer } from 'http' import { on }

    from 'events' import { setTimeout } from 'timers/promises' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { await setTimeout(1000) res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 10 11 import { setTimeout } from 'timers/promises' import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 const server = createServer() 5 server.listen(8000) 6 7 for await (const [req, res] of on(server, 'request')) { 8 await setTimeout(1000) 9 res.end('hello dear friend') 10 } 11 await setTimeout(1000) import { createServer } from 'http' 1 import { on } from 'events' 2 import { setTimeout } from 'timers/promises' 3 4 const server = createServer() 5 server.listen(8000) 6 7 for await (const [req, res] of on(server, 'request')) { 8 9 res.end('hello dear friend') 10 } 11 @loige 60
  167. import { createServer } from 'http' import { on }

    from 'events' import { setTimeout } from 'timers/promises' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { await setTimeout(1000) res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 10 11 import { setTimeout } from 'timers/promises' import { createServer } from 'http' 1 import { on } from 'events' 2 3 4 const server = createServer() 5 server.listen(8000) 6 7 for await (const [req, res] of on(server, 'request')) { 8 await setTimeout(1000) 9 res.end('hello dear friend') 10 } 11 await setTimeout(1000) import { createServer } from 'http' 1 import { on } from 'events' 2 import { setTimeout } from 'timers/promises' 3 4 const server = createServer() 5 server.listen(8000) 6 7 for await (const [req, res] of on(server, 'request')) { 8 9 res.end('hello dear friend') 10 } 11 import { createServer } from 'http' import { on } from 'events' import { setTimeout } from 'timers/promises' const server = createServer() server.listen(8000) for await (const [req, res] of on(server, 'request')) { await setTimeout(1000) res.end('hello dear friend') } 1 2 3 4 5 6 7 8 9 10 11 @loige 60
  168. @loige 61

  169. @loige 61

  170. Let's stick to the basics... 😅 @loige 62

  171. import { createServer } from 'http' import { setTimeout }

    from 'timers/promises' const server = createServer(async function (req, res) { await setTimeout(1000) res.end('hello dear friend') }) server.listen(8000) 1 2 3 4 5 6 7 8 9 @loige 63
  172. import { createServer } from 'http' import { setTimeout }

    from 'timers/promises' const server = createServer(async function (req, res) { await setTimeout(1000) res.end('hello dear friend') }) server.listen(8000) 1 2 3 4 5 6 7 8 9 const server = createServer(async function (req, res) { }) import { createServer } from 'http' 1 import { setTimeout } from 'timers/promises' 2 3 4 await setTimeout(1000) 5 res.end('hello dear friend') 6 7 8 server.listen(8000) 9 @loige 63
  173. import { createServer } from 'http' import { setTimeout }

    from 'timers/promises' const server = createServer(async function (req, res) { await setTimeout(1000) res.end('hello dear friend') }) server.listen(8000) 1 2 3 4 5 6 7 8 9 const server = createServer(async function (req, res) { }) import { createServer } from 'http' 1 import { setTimeout } from 'timers/promises' 2 3 4 await setTimeout(1000) 5 res.end('hello dear friend') 6 7 8 server.listen(8000) 9 import { createServer } from 'http' import { setTimeout } from 'timers/promises' const server = createServer(async function (req, res) { await setTimeout(1000) res.end('hello dear friend') }) server.listen(8000) 1 2 3 4 5 6 7 8 9 @loige 63
  174. @loige 64

  175. @loige 64

  176. Conclusion 🤓 @loige Iterable protocols are a way to standardize

    iteration in JavaScript and Node.js Async iterators are ergonomic tools for sequential asynchronous iteration But don't use them for everything! Consuming data from paginated APIs or reading messages from a queue are good examples! Handling web requests or events from an emitter might not be the best use cases! 65
  177. Want to learn more? @loige - possibly a great book

    😇 - In-depth article on all things iterators - Finding a lost song with Node.js & async iterators nodejsdesignpatterns.com nodejsdesignpatterns.com/blog/javascript-async- iterators/ loige.link/async-it 66
  178. If you enjoyed this talk, you might also enjoy 😛

    nodejsdp.link @loige Let's connect: (blog) (twitter) (twitch) (github) loige.co @loige loige lmammino loige.link/iter 67