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.
Reiterating
JavaScript &
Node.js iterators
Luciano Mammino ( )
@loige
loige.link/iter
RomaJS - June 16, 2021
1
@loige
loige.link/iter
2
How many ways do you
know to "do iteration" in
JavaScript & Node.js?
😰
@loige
3
for i / for...in / for...of
@loige
4
while / do while
@loige
5
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
Object.keys / Object.values /
Object.entries
@loige
7
Iterators / Generators
@loige
8
Spread operator
[...iterable]
@loige
9
Events / Streams
@loige
10
Async iterators / Async generators
@loige
11
for await...of
@loige
12
That was 28 different concepts!
😳
@loige
13
📝 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
Let me introduce myself... @loige
15
Let me introduce myself...
I'm Luciano (
🍕🍝)
👋
@loige
15
Let me introduce myself...
I'm Luciano (
🍕🍝)
👋
Senior Architect
@loige
15
Let me introduce myself...
I'm Luciano (
🍕🍝)
👋
Senior Architect
nodejsdp.link
Co-Author of Node.js Design Patterns
👉
@loige
15
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
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
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
Syntax Review
🧐
@loige
18
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
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
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
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
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
const judoka = 'Ryoko Tani'
for (const char of judoka) {
console.log(char)
}
1
2
3
4
5
@loige
for...of (with strings)
20
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
Iteration Protocols
😵 💫
@loige
27
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
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
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
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
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
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
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
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
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
Iterable protocol
An object is iterable if it implements the @@iterator*
method, a zero-argument function that returns an iterator.
* Symbol.iterator
@loige
30
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
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
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
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
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
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
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
Can an object be both an
iterator and an iterable?!
🤨
@loige
32
const iterableIterator = {
next() {
return { done: false, value: "hello" }
},
[Symbol.iterator]() {
return this
}
}
1
2
3
4
5
6
7
8
@loige
Iterator + Iterable
33
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
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
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
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
Generators
A generator function "produces" an
object that is both an iterator and an
iterable!
🤯
@loige
34
function * createCountdown (start) {
for (let i = start; i >= 0; i--) {
yield i
}
}
1
2
3
4
5
@loige
35
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
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
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
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
Well, what about async
iteration?
@loige
36
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
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
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
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
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
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
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
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
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
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
@loige
39
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
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
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
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
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
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
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
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
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
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
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
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
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
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
@loige
43
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
Tips & pitfalls
☠
@loige
45
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
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
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
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
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
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
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
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
What about
backpressure?
😩
@loige
47
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
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
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
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
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
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
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
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
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
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
But if you are dealing with streaming
pipelines it's probably easier to use
.
pipeline()
@loige
49
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
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
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
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
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
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
In Node.js we can convert any Event
Emitter to an Async Iterator!
😱
@loige
51
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
LAST TIP:
Can we use async iterators to handle
web requests a-la-Deno?
🦕
@loige
56
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
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
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
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
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
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
EASY PEASY LEMON SQUEEZY!
🍋
But... wait, aren't we processing all
requests in series, now?
😱
@loige
58
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
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
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
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
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
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
@loige
61
@loige
61
Let's stick to the basics...
😅
@loige
62
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
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
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
@loige
64
@loige
64
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
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
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