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.

Luciano Mammino

June 16, 2021
Tweet

More Decks by Luciano Mammino

Other Decks in Technology

Transcript

  1. Reiterating
    JavaScript &
    Node.js iterators
    Luciano Mammino ( )
    @loige
    loige.link/iter
    RomaJS - June 16, 2021
    1

    View Slide

  2. @loige
    loige.link/iter
    2

    View Slide

  3. How many ways do you
    know to "do iteration" in
    JavaScript & Node.js?
    😰
    @loige
    3

    View Slide

  4. for i / for...in / for...of
    @loige
    4

    View Slide

  5. while / do while
    @loige
    5

    View Slide

  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

    View Slide

  7. Object.keys / Object.values /
    Object.entries
    @loige
    7

    View Slide

  8. Iterators / Generators
    @loige
    8

    View Slide

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

    View Slide

  10. Events / Streams
    @loige
    10

    View Slide

  11. Async iterators / Async generators
    @loige
    11

    View Slide

  12. for await...of
    @loige
    12

    View Slide

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

    View Slide

  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

    View Slide

  15. Let me introduce myself... @loige
    15

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  22. Syntax Review
    🧐
    @loige
    18

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  49. Iteration Protocols
    😵 💫
    @loige
    27

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  67. Can an object be both an
    iterator and an iterable?!
    🤨
    @loige
    32

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  73. Generators
    A generator function "produces" an
    object that is both an iterator and an
    iterable!
    🤯
    @loige
    34

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  79. Well, what about async
    iteration?
    @loige
    36

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  90. @loige
    39

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  105. @loige
    43

    View Slide

  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

    View Slide

  107. Tips & pitfalls

    @loige
    45

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  116. What about
    backpressure?
    😩
    @loige
    47

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  127. But if you are dealing with streaming
    pipelines it's probably easier to use
    .
    pipeline()
    @loige
    49

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  134. In Node.js we can convert any Event
    Emitter to an Async Iterator!
    😱
    @loige
    51

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  154. LAST TIP:
    Can we use async iterators to handle
    web requests a-la-Deno?
    🦕
    @loige
    56

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  161. EASY PEASY LEMON SQUEEZY!
    🍋
    But... wait, aren't we processing all
    requests in series, now?
    😱
    @loige
    58

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  168. @loige
    61

    View Slide

  169. @loige
    61

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  174. @loige
    64

    View Slide

  175. @loige
    64

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide