Slide 1

Slide 1 text

K Y I V 2 0 1 9 Luciano Mammino (@loige) IT’S ABOUT TIME TO IT’S ABOUT TIME TO EMBRACE STREAMS EMBRACE STREAMS loige.link/streams-kyiv May 18th 1

Slide 2

Slide 2 text

// buffer-copy.js const { readFileSync, writeFileSync } = require('fs') const [,, src, dest] = process.argv // read entire file content const content = readFileSync(src) // write that content somewhere else writeFileSync(dest, content) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 @loige 2

Slide 3

Slide 3 text

// buffer-copy.js const { readFileSync, writeFileSync } = require('fs') const [,, src, dest] = process.argv // read entire file content const content = readFileSync(src) // write that content somewhere else writeFileSync(dest, content) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const { readFileSync, writeFileSync } = require('fs') // buffer-copy.js 1 2 3 4 5 6 7 const [,, src, dest] = process.argv 8 9 // read entire file content 10 const content = readFileSync(src) 11 12 // write that content somewhere else 13 writeFileSync(dest, content) 14 @loige 2

Slide 4

Slide 4 text

// buffer-copy.js const { readFileSync, writeFileSync } = require('fs') const [,, src, dest] = process.argv // read entire file content const content = readFileSync(src) // write that content somewhere else writeFileSync(dest, content) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const { readFileSync, writeFileSync } = require('fs') // buffer-copy.js 1 2 3 4 5 6 7 const [,, src, dest] = process.argv 8 9 // read entire file content 10 const content = readFileSync(src) 11 12 // write that content somewhere else 13 writeFileSync(dest, content) 14 // read entire file content const content = readFileSync(src) // buffer-copy.js 1 2 const { 3 readFileSync, 4 writeFileSync 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 9 10 11 12 // write that content somewhere else 13 writeFileSync(dest, content) 14 @loige 2

Slide 5

Slide 5 text

// buffer-copy.js const { readFileSync, writeFileSync } = require('fs') const [,, src, dest] = process.argv // read entire file content const content = readFileSync(src) // write that content somewhere else writeFileSync(dest, content) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const { readFileSync, writeFileSync } = require('fs') // buffer-copy.js 1 2 3 4 5 6 7 const [,, src, dest] = process.argv 8 9 // read entire file content 10 const content = readFileSync(src) 11 12 // write that content somewhere else 13 writeFileSync(dest, content) 14 // read entire file content const content = readFileSync(src) // buffer-copy.js 1 2 const { 3 readFileSync, 4 writeFileSync 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 9 10 11 12 // write that content somewhere else 13 writeFileSync(dest, content) 14 // write that content somewhere else writeFileSync(dest, content) // buffer-copy.js 1 2 const { 3 readFileSync, 4 writeFileSync 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 9 // read entire file content 10 const content = readFileSync(src) 11 12 13 14 @loige 2

Slide 6

Slide 6 text

@loige 3

Slide 7

Slide 7 text

WE DO THIS ALL THE TIME WE DO THIS ALL THE TIME @loige 3

Slide 8

Slide 8 text

WE DO THIS ALL THE TIME WE DO THIS ALL THE TIME AND IT'S OK AND IT'S OK @loige 3

Slide 9

Slide 9 text

WE DO THIS ALL THE TIME WE DO THIS ALL THE TIME AND IT'S OK AND IT'S OK BUT SOMETIMES ... BUT SOMETIMES ... @loige 3

Slide 10

Slide 10 text

@loige ERR_FS_FILE_TOO_LARGE! ERR_FS_FILE_TOO_LARGE! File size is greater than possible Buffer 4

Slide 11

Slide 11 text

BUT WHY? BUT WHY? @loige 5

Slide 12

Slide 12 text

IF BYTES IF BYTES WERE WERE BLOCKS... BLOCKS... @loige 6

Slide 13

Slide 13 text

MARIO CAN LIFT MARIO CAN LIFT FEW BLOCKS FEW BLOCKS @loige 7

Slide 14

Slide 14 text

BUT NOT TOO MANY... BUT NOT TOO MANY... @loige ?! 8

Slide 15

Slide 15 text

WHAT CAN WE DO IF WE HAVE TO WHAT CAN WE DO IF WE HAVE TO MOVE MANY BLOCKS? MOVE MANY BLOCKS? @loige 9

Slide 16

Slide 16 text

WE CAN MOVE THEM ONE BY ONE! WE CAN MOVE THEM ONE BY ONE! @loige we stream them... 10

Slide 17

Slide 17 text

11

Slide 18

Slide 18 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! 11

Slide 19

Slide 19 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! 11

Slide 20

Slide 20 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! 11

Slide 21

Slide 21 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! 11

Slide 22

Slide 22 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! Cloud Architect 11

Slide 23

Slide 23 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! Cloud Architect Blog: Twitter: GitHub: loige.co @loige @lmammino 11

Slide 24

Slide 24 text

HELLO, I AM LUCIANO! HELLO, I AM LUCIANO! Cloud Architect Blog: Twitter: GitHub: loige.co @loige @lmammino 11

Slide 25

Slide 25 text

code: loige.link/streams-examples loige.link/streams-kyiv 12

Slide 26

Slide 26 text

01. BUFFERS VS 01. BUFFERS VS STREAMS STREAMS @loige 13

Slide 27

Slide 27 text

BUFFER BUFFER: DATA STRUCTURE TO STORE AND : DATA STRUCTURE TO STORE AND TRANSFER ARBITRARY BINARY DATA TRANSFER ARBITRARY BINARY DATA @loige *Note that this is loading all the content of the file in memory * 14

Slide 28

Slide 28 text

STREAM STREAM: ABSTRACT INTERFACE FOR : ABSTRACT INTERFACE FOR WORKING WITH STREAMING DATA WORKING WITH STREAMING DATA @loige *It does not load all the data straight away * 15

Slide 29

Slide 29 text

FILE COPY: FILE COPY: THE BUFFER WAY THE BUFFER WAY @loige // buffer-copy.js const { readFileSync, writeFileSync } = require('fs') const [,, src, dest] = process.argv const content = readFileSync(src) writeFileSync(dest, content) 1 2 3 4 5 6 7 8 9 10 16

Slide 30

Slide 30 text

FILE COPY: FILE COPY: THE STREAM WAY THE STREAM WAY // stream-copy.js const { createReadStream, createWriteStream } = require('fs') const [,, src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', (data) => destStream.write(data)) 1 2 3 4 5 6 7 8 9 10 11 @loige * Careful: this implementation is not optimal * 17

Slide 31

Slide 31 text

FILE COPY: FILE COPY: THE STREAM WAY THE STREAM WAY // stream-copy.js const { createReadStream, createWriteStream } = require('fs') const [,, src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', (data) => destStream.write(data)) 1 2 3 4 5 6 7 8 9 10 11 createReadStream, createWriteStream // stream-copy.js 1 2 const { 3 4 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 const srcStream = createReadStream(src) 9 const destStream = createWriteStream(dest) 10 srcStream.on('data', (data) => destStream.write(data)) 11 @loige * Careful: this implementation is not optimal * 17

Slide 32

Slide 32 text

FILE COPY: FILE COPY: THE STREAM WAY THE STREAM WAY // stream-copy.js const { createReadStream, createWriteStream } = require('fs') const [,, src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', (data) => destStream.write(data)) 1 2 3 4 5 6 7 8 9 10 11 createReadStream, createWriteStream // stream-copy.js 1 2 const { 3 4 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 const srcStream = createReadStream(src) 9 const destStream = createWriteStream(dest) 10 srcStream.on('data', (data) => destStream.write(data)) 11 const srcStream = createReadStream(src) const destStream = createWriteStream(dest) // stream-copy.js 1 2 const { 3 createReadStream, 4 createWriteStream 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 9 10 srcStream.on('data', (data) => destStream.write(data)) 11 @loige * Careful: this implementation is not optimal * 17

Slide 33

Slide 33 text

FILE COPY: FILE COPY: THE STREAM WAY THE STREAM WAY // stream-copy.js const { createReadStream, createWriteStream } = require('fs') const [,, src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', (data) => destStream.write(data)) 1 2 3 4 5 6 7 8 9 10 11 createReadStream, createWriteStream // stream-copy.js 1 2 const { 3 4 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 const srcStream = createReadStream(src) 9 const destStream = createWriteStream(dest) 10 srcStream.on('data', (data) => destStream.write(data)) 11 const srcStream = createReadStream(src) const destStream = createWriteStream(dest) // stream-copy.js 1 2 const { 3 createReadStream, 4 createWriteStream 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 9 10 srcStream.on('data', (data) => destStream.write(data)) 11 srcStream.on('data', (data) => destStream.write(data)) // stream-copy.js 1 2 const { 3 createReadStream, 4 createWriteStream 5 } = require('fs') 6 7 const [,, src, dest] = process.argv 8 const srcStream = createReadStream(src) 9 const destStream = createWriteStream(dest) 10 11 @loige * Careful: this implementation is not optimal * 17

Slide 34

Slide 34 text

MEMORY COMPARISON (~600MB FILE) MEMORY COMPARISON (~600MB FILE) node ­­inspect­brk buffer­copy.js assets/poster.psd ~/Downloads/poster.psd @loige 18

Slide 35

Slide 35 text

MEMORY COMPARISON (~600MB FILE) MEMORY COMPARISON (~600MB FILE) node ­­inspect­brk stream­copy.js assets/poster.psd ~/Downloads/poster.psd @loige 19

Slide 36

Slide 36 text

LET'S TRY WITH A BIG FILE (~10GB) LET'S TRY WITH A BIG FILE (~10GB) @loige 20

Slide 37

Slide 37 text

LET'S TRY WITH A BIG FILE (~10GB) LET'S TRY WITH A BIG FILE (~10GB) node ­­inspect­brk stream­copy.js assets/the­matrix­hd.mkv ~/Downloads/the­matrix­hd.mkv @loige 21

Slide 38

Slide 38 text

STREAMS VS BUFFERS STREAMS VS BUFFERS Streams keep a low memory footprint even with large amounts of data Streams allows you to process data as soon as it arrives @loige 22

Slide 39

Slide 39 text

03. STREAM TYPES 03. STREAM TYPES & APIS & APIS @loige 23

Slide 40

Slide 40 text

ALL STREAMS ARE ALL STREAMS ARE EVENT EMITTERS EVENT EMITTERS A stream instance is an object that emits events when its internal state changes, for instance: s.on('readable', () => {}) // ready to be consumed s.on('data', (chunk) => {}) // new data is available s.on('error', (err) => {}) // some error happened s.on('end', () => {}) // no more data available The events available depend from the type of stream @loige 24

Slide 41

Slide 41 text

READABLE READABLE STREAMS STREAMS A readable stream represents a source from which data is consumed. Examples: fs readStream process.stdin HTTP response (client-side) HTTP request (server-side) AWS S3 GetObject (data field) It supports two modes for data consumption: flowing and paused (or non- flowing) mode. @loige 25

Slide 42

Slide 42 text

READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. @loige 26

Slide 43

Slide 43 text

@loige 1 2 3 Source data Readable stream in flowing mode data listener READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 27

Slide 44

Slide 44 text

@loige 1 2 3 Source data Readable stream in flowing mode Read data listener READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 28

Slide 45

Slide 45 text

@loige 1 2 3 Source data Readable stream in flowing mode data listener data READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 29

Slide 46

Slide 46 text

@loige 2 3 Source data Readable stream in flowing mode data listener Read READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 30

Slide 47

Slide 47 text

@loige 2 3 Source data Readable stream in flowing mode data listener data READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 31

Slide 48

Slide 48 text

@loige 3 Source data Readable stream in flowing mode data listener Read READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 32

Slide 49

Slide 49 text

@loige 3 Source data Readable stream in flowing mode data listener data READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 33

Slide 50

Slide 50 text

@loige Source data Readable stream in flowing mode Read data listener (end) READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 34

Slide 51

Slide 51 text

@loige Source data Readable stream in flowing mode data listener end (end) When no more data is available, end is emitted. READABLE STREAMS READABLE STREAMS Data is read from source automatically and chunks are emitted as soon as they are available. 35

Slide 52

Slide 52 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @loige 36

Slide 53

Slide 53 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 54

Slide 54 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 const file = createReadStream(process.argv[2]) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 55

Slide 55 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 const file = createReadStream(process.argv[2]) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 let counter = 0 // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 56

Slide 56 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 const file = createReadStream(process.argv[2]) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 let counter = 0 // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 file.on('data', chunk => { }) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 57

Slide 57 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 const file = createReadStream(process.argv[2]) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 let counter = 0 // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 file.on('data', chunk => { }) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 for (let char of chunk.toString('utf8')) { } // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 58

Slide 58 text

// count-emojis-flowing.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 file.on('data', chunk => { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } }) file.on('end', () => console.log(`Found ${counter} emojis`)) file.on('error', err => console.error(`Error reading file: ${err}`)) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const { EMOJI_MAP } = require('emoji') // from npm // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 const file = createReadStream(process.argv[2]) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 let counter = 0 // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 file.on('data', chunk => { }) // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 11 for (let char of chunk.toString('utf8')) { 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 } 16 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 for (let char of chunk.toString('utf8')) { } // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 12 if (emojis.includes(char)) { 13 counter++ 14 } 15 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 if (emojis.includes(char)) { counter++ } // count-emojis-flowing.js 1 2 const { createReadStream } = require('fs') 3 const { EMOJI_MAP } = require('emoji') // from npm 4 5 const emojis = Object.keys(EMOJI_MAP) 6 7 const file = createReadStream(process.argv[2]) 8 let counter = 0 9 10 file.on('data', chunk => { 11 for (let char of chunk.toString('utf8')) { 12 13 14 15 } 16 }) 17 file.on('end', () => console.log(`Found ${counter} emojis`)) 18 file.on('error', err => console.error(`Error reading file: ${err}`)) 19 @loige 36

Slide 59

Slide 59 text

loige.link/up-emojiart @loige 37

Slide 60

Slide 60 text

READABLE STREAMS ARE READABLE STREAMS ARE ALSO ALSO ASYNC ITERATORS ASYNC ITERATORS ( (NODE.JS 10+) NODE.JS 10+) @loige 38

Slide 61

Slide 61 text

// count-emojis-async-iterator.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm async function main () { const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 for await (let chunk of file) { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } } console.log(`Found ${counter} emojis`) } main() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @loige 39

Slide 62

Slide 62 text

// count-emojis-async-iterator.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm async function main () { const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 for await (let chunk of file) { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } } console.log(`Found ${counter} emojis`) } main() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 for await (let chunk of file) { } // count-emojis-async-iterator.js 1 const { createReadStream } = require('fs') 2 const { EMOJI_MAP } = require('emoji') // from npm 3 4 async function main () { 5 const emojis = Object.keys(EMOJI_MAP) 6 const file = createReadStream(process.argv[2]) 7 let counter = 0 8 9 10 for (let char of chunk.toString('utf8')) { 11 if (emojis.includes(char)) { 12 counter++ 13 } 14 } 15 16 17 console.log(`Found ${counter} emojis`) 18 } 19 20 main() 21 @loige 39

Slide 63

Slide 63 text

// count-emojis-async-iterator.js const { createReadStream } = require('fs') const { EMOJI_MAP } = require('emoji') // from npm async function main () { const emojis = Object.keys(EMOJI_MAP) const file = createReadStream(process.argv[2]) let counter = 0 for await (let chunk of file) { for (let char of chunk.toString('utf8')) { if (emojis.includes(char)) { counter++ } } } console.log(`Found ${counter} emojis`) } main() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 for await (let chunk of file) { } // count-emojis-async-iterator.js 1 const { createReadStream } = require('fs') 2 const { EMOJI_MAP } = require('emoji') // from npm 3 4 async function main () { 5 const emojis = Object.keys(EMOJI_MAP) 6 const file = createReadStream(process.argv[2]) 7 let counter = 0 8 9 10 for (let char of chunk.toString('utf8')) { 11 if (emojis.includes(char)) { 12 counter++ 13 } 14 } 15 16 17 console.log(`Found ${counter} emojis`) 18 } 19 20 main() 21 async function main () { } // count-emojis-async-iterator.js 1 const { createReadStream } = require('fs') 2 const { EMOJI_MAP } = require('emoji') // from npm 3 4 5 const emojis = Object.keys(EMOJI_MAP) 6 const file = createReadStream(process.argv[2]) 7 let counter = 0 8 9 for await (let chunk of file) { 10 for (let char of chunk.toString('utf8')) { 11 if (emojis.includes(char)) { 12 counter++ 13 } 14 } 15 } 16 17 console.log(`Found ${counter} emojis`) 18 19 20 main() 21 @loige 39

Slide 64

Slide 64 text

WRITABLE WRITABLE STREAMS STREAMS A writable stream is an abstraction that allows to write data over a destination Examples: fs writeStream process.stdout, process.stderr HTTP request (client-side) HTTP response (server-side) AWS S3 PutObject (body parameter) @loige 40

Slide 65

Slide 65 text

// writable-http-request.js const http = require('http') const req = http.request( { hostname: 'enx6b07hdu6cs.x.pipedream.net', method: 'POST' }, resp => { console.log(`Server responded with "${resp.statusCode}"`) } ) req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) req.write('writing some content...\n') req.end('last write & close the stream') 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @loige 41

Slide 66

Slide 66 text

// writable-http-request.js const http = require('http') const req = http.request( { hostname: 'enx6b07hdu6cs.x.pipedream.net', method: 'POST' }, resp => { console.log(`Server responded with "${resp.statusCode}"`) } ) req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) req.write('writing some content...\n') req.end('last write & close the stream') 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const req = http.request( ) // writable-http-request.js 1 const http = require('http') 2 3 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 12 13 req.on('finish', () => console.log('request sent')) 14 req.on('close', () => console.log('Connection closed')) 15 req.on('error', err => console.error(`Request failed: ${err}`)) 16 17 req.write('writing some content...\n') 18 req.end('last write & close the stream') 19 @loige 41

Slide 67

Slide 67 text

// writable-http-request.js const http = require('http') const req = http.request( { hostname: 'enx6b07hdu6cs.x.pipedream.net', method: 'POST' }, resp => { console.log(`Server responded with "${resp.statusCode}"`) } ) req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) req.write('writing some content...\n') req.end('last write & close the stream') 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const req = http.request( ) // writable-http-request.js 1 const http = require('http') 2 3 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 12 13 req.on('finish', () => console.log('request sent')) 14 req.on('close', () => console.log('Connection closed')) 15 req.on('error', err => console.error(`Request failed: ${err}`)) 16 17 req.write('writing some content...\n') 18 req.end('last write & close the stream') 19 req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) // writable-http-request.js 1 const http = require('http') 2 3 const req = http.request( 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 ) 12 13 14 15 16 17 req.write('writing some content...\n') 18 req.end('last write & close the stream') 19 @loige 41

Slide 68

Slide 68 text

// writable-http-request.js const http = require('http') const req = http.request( { hostname: 'enx6b07hdu6cs.x.pipedream.net', method: 'POST' }, resp => { console.log(`Server responded with "${resp.statusCode}"`) } ) req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) req.write('writing some content...\n') req.end('last write & close the stream') 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const req = http.request( ) // writable-http-request.js 1 const http = require('http') 2 3 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 12 13 req.on('finish', () => console.log('request sent')) 14 req.on('close', () => console.log('Connection closed')) 15 req.on('error', err => console.error(`Request failed: ${err}`)) 16 17 req.write('writing some content...\n') 18 req.end('last write & close the stream') 19 req.on('finish', () => console.log('request sent')) req.on('close', () => console.log('Connection closed')) req.on('error', err => console.error(`Request failed: ${err}`)) // writable-http-request.js 1 const http = require('http') 2 3 const req = http.request( 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 ) 12 13 14 15 16 17 req.write('writing some content...\n') 18 req.end('last write & close the stream') 19 req.write('writing some content...\n') req.end('last write & close the stream') // writable-http-request.js 1 const http = require('http') 2 3 const req = http.request( 4 { 5 hostname: 'enx6b07hdu6cs.x.pipedream.net', 6 method: 'POST' 7 }, 8 resp => { 9 console.log(`Server responded with "${resp.statusCode}"`) 10 } 11 ) 12 13 req.on('finish', () => console.log('request sent')) 14 req.on('close', () => console.log('Connection closed')) 15 req.on('error', err => console.error(`Request failed: ${err}`)) 16 17 18 19 @loige 41

Slide 69

Slide 69 text

@loige 42

Slide 70

Slide 70 text

loige.link/writable-http-req @loige 43

Slide 71

Slide 71 text

BACKPRESSURE BACKPRESSURE When writing large amounts of data you should make sure you handle the stop write signal and the drain event loige.link/backpressure @loige 44

Slide 72

Slide 72 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @loige 45

Slide 73

Slide 73 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const canContinue = destStream.write(data) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 @loige 45

Slide 74

Slide 74 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const canContinue = destStream.write(data) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 if (!canContinue) { } // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 16 }) 17 @loige 45

Slide 75

Slide 75 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const canContinue = destStream.write(data) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 if (!canContinue) { } // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 16 }) 17 // we are overflowing the destination, we should pause srcStream.pause() // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 if (!canContinue) { 11 12 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 @loige 45

Slide 76

Slide 76 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const canContinue = destStream.write(data) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 if (!canContinue) { } // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 16 }) 17 // we are overflowing the destination, we should pause srcStream.pause() // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 if (!canContinue) { 11 12 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 14 15 } 16 }) 17 @loige 45

Slide 77

Slide 77 text

// stream-copy-safe.js const { createReadStream, createWriteStream } = require('fs') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } }) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const canContinue = destStream.write(data) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 if (!canContinue) { } // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 16 }) 17 // we are overflowing the destination, we should pause srcStream.pause() // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 if (!canContinue) { 11 12 13 // we will resume when the destination stream is drained 14 destStream.once('drain', () => srcStream.resume()) 15 } 16 }) 17 // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 const canContinue = destStream.write(data) 10 if (!canContinue) { 11 // we are overflowing the destination, we should pause 12 srcStream.pause() 13 14 15 } 16 }) 17 const canContinue = destStream.write(data) if (!canContinue) { // we are overflowing the destination, we should pause srcStream.pause() // we will resume when the destination stream is drained destStream.once('drain', () => srcStream.resume()) } // stream-copy-safe.js 1 2 const { createReadStream, createWriteStream } = require('fs') 3 4 const [, , src, dest] = process.argv 5 const srcStream = createReadStream(src) 6 const destStream = createWriteStream(dest) 7 8 srcStream.on('data', data => { 9 10 11 12 13 14 15 16 }) 17 @loige 45

Slide 78

Slide 78 text

OTHER TYPES OF STREAM OTHER TYPES OF STREAM Duplex Stream streams that are both Readable and Writable. (net.Socket) Transform Stream Duplex streams that can modify or transform the data as it is written and read. (zlib.createGzip(), crypto.createCipheriv()) @loige 46

Slide 79

Slide 79 text

ANATOMY OF A TRANSFORM STREAM ANATOMY OF A TRANSFORM STREAM transform stream @loige 47

Slide 80

Slide 80 text

ANATOMY OF A TRANSFORM STREAM ANATOMY OF A TRANSFORM STREAM 1. write data transform stream (readable stream) @loige 47

Slide 81

Slide 81 text

ANATOMY OF A TRANSFORM STREAM ANATOMY OF A TRANSFORM STREAM 1. write data transform stream 2. transform the data (readable stream) @loige 47

Slide 82

Slide 82 text

ANATOMY OF A TRANSFORM STREAM ANATOMY OF A TRANSFORM STREAM 1. write data transform stream 3. read transformed data 2. transform the data (readable stream) (writable stream) @loige 47

Slide 83

Slide 83 text

GZIP EXAMPLE GZIP EXAMPLE 1. write data transform stream 3. read transformed data 2. transform the data (readable stream) (writable stream) @loige 48

Slide 84

Slide 84 text

GZIP EXAMPLE GZIP EXAMPLE 1. write data transform stream 3. read transformed data 2. transform the data (readable stream) (writable stream) @loige Uncompressed data 48

Slide 85

Slide 85 text

GZIP EXAMPLE GZIP EXAMPLE 1. write data transform stream 3. read transformed data 2. transform the data (readable stream) (writable stream) @loige Uncompressed data compress zlib.createGzip() 48

Slide 86

Slide 86 text

GZIP EXAMPLE GZIP EXAMPLE 1. write data transform stream 3. read transformed data 2. transform the data (readable stream) (writable stream) @loige Uncompressed data Compressed data compress zlib.createGzip() 48

Slide 87

Slide 87 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable 49 @loige

Slide 88

Slide 88 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data 49 @loige

Slide 89

Slide 89 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() 49 @loige

Slide 90

Slide 90 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data 49 @loige

Slide 91

Slide 91 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() 49 @loige

Slide 92

Slide 92 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() 49 @loige (Backpressure)

Slide 93

Slide 93 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() 49 @loige (Backpressure)

Slide 94

Slide 94 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain 49 @loige (Backpressure)

Slide 95

Slide 95 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() 49 @loige (Backpressure)

Slide 96

Slide 96 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() 49 @loige (Backpressure) (Backpressure)

Slide 97

Slide 97 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() pause() 49 @loige (Backpressure) (Backpressure)

Slide 98

Slide 98 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() pause() ⚡ drain 49 @loige (Backpressure) (Backpressure)

Slide 99

Slide 99 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() pause() ⚡ drain resume() 49 @loige (Backpressure) (Backpressure)

Slide 100

Slide 100 text

HOW CAN WE USE TRANSFORM STREAMS? HOW CAN WE USE TRANSFORM STREAMS? Readable Transform Writable ⚡ data write() ⚡ data write() pause() ⚡ drain resume() pause() ⚡ drain resume() 49 @loige (Backpressure) (Backpressure) You also have to handle end & error events!

Slide 101

Slide 101 text

gzipStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { gzipStream.pause() destStream.once('drain', () => { gzipStream.resume() }) } }) gzipStream.on('end', () => { destStream.end() }) // ⚠ TODO: handle errors! // stream-copy-gzip.js const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const gzipStream = createGzip() const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = gzipStream.write(data) if (!canContinue) { srcStream.pause() gzipStream.once('drain', () => { srcStream.resume() }) } }) srcStream.on('end', () => { // check if there's buffered data left const remainingData = gzipStream.read() if (remainingData !== null) { destStream.write() } gzipStream.end() }) @loige 50

Slide 102

Slide 102 text

gzipStream.on('data', data => { const canContinue = destStream.write(data) if (!canContinue) { gzipStream.pause() destStream.once('drain', () => { gzipStream.resume() }) } }) gzipStream.on('end', () => { destStream.end() }) // ⚠ TODO: handle errors! // stream-copy-gzip.js const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const gzipStream = createGzip() const destStream = createWriteStream(dest) srcStream.on('data', data => { const canContinue = gzipStream.write(data) if (!canContinue) { srcStream.pause() gzipStream.once('drain', () => { srcStream.resume() }) } }) srcStream.on('end', () => { // check if there's buffered data left const remainingData = gzipStream.read() if (remainingData !== null) { destStream.write() } gzipStream.end() }) @loige 50

Slide 103

Slide 103 text

03. PIPE() 03. PIPE() @loige 51

Slide 104

Slide 104 text

readable .pipe(tranform1) .pipe(transform2) .pipe(transform3) .pipe(writable) readable.pipe(writableDest) @loige Connects a readable stream to a writable stream A transform stream can be used as a destination as well It returns the destination stream allowing for a chain of pipes 52

Slide 105

Slide 105 text

// stream-copy-gzip-pipe.js const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const gzipStream = createGzip() const destStream = createWriteStream(dest) srcStream .pipe(gzipStream) .pipe(destStream) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @loige 53

Slide 106

Slide 106 text

// stream-copy-gzip-pipe.js const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv const srcStream = createReadStream(src) const gzipStream = createGzip() const destStream = createWriteStream(dest) srcStream .pipe(gzipStream) .pipe(destStream) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 srcStream .pipe(gzipStream) .pipe(destStream) // stream-copy-gzip-pipe.js 1 2 const { 3 createReadStream, 4 createWriteStream 5 } = require('fs') 6 const { createGzip } = require('zlib') 7 8 const [, , src, dest] = process.argv 9 const srcStream = createReadStream(src) 10 const gzipStream = createGzip() 11 const destStream = createWriteStream(dest) 12 13 14 15 16 @loige 53

Slide 107

Slide 107 text

readable .pipe(decompress) .pipe(decrypt) .pipe(convert) .pipe(encrypt) .pipe(compress) .pipe(writeToDisk) Setup complex pipelines with pipe @loige This is the most common way to use streams 54

Slide 108

Slide 108 text

readable .on('error', handleErr) .pipe(decompress) .on('error', handleErr) .pipe(decrypt) .on('error', handleErr) .pipe(convert) .on('error', handleErr) .pipe(encrypt) .on('error', handleErr) .pipe(compress) .on('error', handleErr) .pipe(writeToDisk) .on('error', handleErr) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Handling errors (correctly) @loige 55

Slide 109

Slide 109 text

readable .on('error', handleErr) .pipe(decompress) .on('error', handleErr) .pipe(decrypt) .on('error', handleErr) .pipe(convert) .on('error', handleErr) .pipe(encrypt) .on('error', handleErr) .pipe(compress) .on('error', handleErr) .pipe(writeToDisk) .on('error', handleErr) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 readable .pipe(decompress) .pipe(decrypt) .pipe(convert) .pipe(encrypt) .pipe(compress) .pipe(writeToDisk) 1 .on('error', handleErr) 2 3 .on('error', handleErr) 4 5 .on('error', handleErr) 6 7 .on('error', handleErr) 8 9 .on('error', handleErr) 10 11 .on('error', handleErr) 12 13 .on('error', handleErr) 14 Handling errors (correctly) @loige 55

Slide 110

Slide 110 text

readable .on('error', handleErr) .pipe(decompress) .on('error', handleErr) .pipe(decrypt) .on('error', handleErr) .pipe(convert) .on('error', handleErr) .pipe(encrypt) .on('error', handleErr) .pipe(compress) .on('error', handleErr) .pipe(writeToDisk) .on('error', handleErr) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 readable .pipe(decompress) .pipe(decrypt) .pipe(convert) .pipe(encrypt) .pipe(compress) .pipe(writeToDisk) 1 .on('error', handleErr) 2 3 .on('error', handleErr) 4 5 .on('error', handleErr) 6 7 .on('error', handleErr) 8 9 .on('error', handleErr) 10 11 .on('error', handleErr) 12 13 .on('error', handleErr) 14 .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) readable 1 2 .pipe(decompress) 3 4 .pipe(decrypt) 5 6 .pipe(convert) 7 8 .pipe(encrypt) 9 10 .pipe(compress) 11 12 .pipe(writeToDisk) 13 14 Handling errors (correctly) @loige handleErr should end and destroy the streams (it doesn't happen automatically) 55

Slide 111

Slide 111 text

readable .on('error', handleErr) .pipe(decompress) .on('error', handleErr) .pipe(decrypt) .on('error', handleErr) .pipe(convert) .on('error', handleErr) .pipe(encrypt) .on('error', handleErr) .pipe(compress) .on('error', handleErr) .pipe(writeToDisk) .on('error', handleErr) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 readable .pipe(decompress) .pipe(decrypt) .pipe(convert) .pipe(encrypt) .pipe(compress) .pipe(writeToDisk) 1 .on('error', handleErr) 2 3 .on('error', handleErr) 4 5 .on('error', handleErr) 6 7 .on('error', handleErr) 8 9 .on('error', handleErr) 10 11 .on('error', handleErr) 12 13 .on('error', handleErr) 14 .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) .on('error', handleErr) readable 1 2 .pipe(decompress) 3 4 .pipe(decrypt) 5 6 .pipe(convert) 7 8 .pipe(encrypt) 9 10 .pipe(compress) 11 12 .pipe(writeToDisk) 13 14 Handling errors (correctly) @loige handleErr should end and destroy the streams (it doesn't happen automatically) 55

Slide 112

Slide 112 text

04. STREAM UTILITIES 04. STREAM UTILITIES @loige 56

Slide 113

Slide 113 text

// stream-copy-gzip-pipeline.js const { pipeline } = require('stream') const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pipeline( createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 stream.pipeline(...streams, callback) - Node.js 10+ @loige 57

Slide 114

Slide 114 text

// stream-copy-gzip-pipeline.js const { pipeline } = require('stream') const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pipeline( createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const { pipeline } = require('stream') pipeline( ) // stream-copy-gzip-pipeline.js 1 2 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 21 stream.pipeline(...streams, callback) - Node.js 10+ @loige 57

Slide 115

Slide 115 text

// stream-copy-gzip-pipeline.js const { pipeline } = require('stream') const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pipeline( createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const { pipeline } = require('stream') pipeline( ) // stream-copy-gzip-pipeline.js 1 2 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 21 createReadStream(src), createGzip(), createWriteStream(dest), // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 10 11 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 ) 21 stream.pipeline(...streams, callback) - Node.js 10+ @loige You can pass multiple streams (they will be piped) 57

Slide 116

Slide 116 text

// stream-copy-gzip-pipeline.js const { pipeline } = require('stream') const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pipeline( createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const { pipeline } = require('stream') pipeline( ) // stream-copy-gzip-pipeline.js 1 2 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 21 createReadStream(src), createGzip(), createWriteStream(dest), // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 10 11 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 ) 21 function onEnd (err) { } // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 20 ) 21 stream.pipeline(...streams, callback) - Node.js 10+ @loige You can pass multiple streams (they will be piped) 57

Slide 117

Slide 117 text

// stream-copy-gzip-pipeline.js const { pipeline } = require('stream') const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pipeline( createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const { pipeline } = require('stream') pipeline( ) // stream-copy-gzip-pipeline.js 1 2 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 21 createReadStream(src), createGzip(), createWriteStream(dest), // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 10 11 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 ) 21 function onEnd (err) { } // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 20 ) 21 if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') // stream-copy-gzip-pipeline.js 1 2 const { pipeline } = require('stream') 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 pipeline( 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 14 15 16 17 18 19 } 20 ) 21 stream.pipeline(...streams, callback) - Node.js 10+ @loige You can pass multiple streams (they will be piped) The last argument is a callback. If invoked with an error, it means the pipeline failed at some point. All the streams are ended and destroyed correctly. 57

Slide 118

Slide 118 text

// stream-copy-gzip-pump.js const pump = require('pump') // from npm const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pump( // just swap pipeline with pump! createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 For Node.js < 10: pump - npm.im/pump @loige 58

Slide 119

Slide 119 text

// stream-copy-gzip-pump.js const pump = require('pump') // from npm const { createReadStream, createWriteStream } = require('fs') const { createGzip } = require('zlib') const [, , src, dest] = process.argv pump( // just swap pipeline with pump! createReadStream(src), createGzip(), createWriteStream(dest), function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } console.log('Done!') } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const pump = require('pump') // from npm pump( // just swap pipeline with pump! ) // stream-copy-gzip-pump.js 1 2 3 const { createReadStream, createWriteStream } = require('fs') 4 const { createGzip } = require('zlib') 5 6 const [, , src, dest] = process.argv 7 8 9 createReadStream(src), 10 createGzip(), 11 createWriteStream(dest), 12 function onEnd (err) { 13 if (err) { 14 console.error(`Error: ${err}`) 15 process.exit(1) 16 } 17 18 console.log('Done!') 19 } 20 21 For Node.js < 10: pump - npm.im/pump @loige 58

Slide 120

Slide 120 text

pumpify(...streams) - Create reusable pieces of pipeline npm.im/pumpify @loige Let's create EncGz, an application that helps us to read and write encrypted- gzipped files 59

Slide 121

Slide 121 text

// encgz-stream.js - utility library const { createCipheriv, createDecipheriv, randomBytes, createHash } = require('crypto') const { createGzip, createGunzip } = require('zlib') const pumpify = require('pumpify') // from npm // calculates md5 of the secret (trimmed) function getChiperKey (secret) {} function createEncgz (secret) { const initVect = randomBytes(16) const cipherKey = getChiperKey(secret) const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() const stream = pumpify(encryptStream, gzipStream) stream.initVect = initVect return stream } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @loige 60

Slide 122

Slide 122 text

// encgz-stream.js - utility library const { createCipheriv, createDecipheriv, randomBytes, createHash } = require('crypto') const { createGzip, createGunzip } = require('zlib') const pumpify = require('pumpify') // from npm // calculates md5 of the secret (trimmed) function getChiperKey (secret) {} function createEncgz (secret) { const initVect = randomBytes(16) const cipherKey = getChiperKey(secret) const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() const stream = pumpify(encryptStream, gzipStream) stream.initVect = initVect return stream } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function createEncgz (secret) { } // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 25 @loige 60

Slide 123

Slide 123 text

// encgz-stream.js - utility library const { createCipheriv, createDecipheriv, randomBytes, createHash } = require('crypto') const { createGzip, createGunzip } = require('zlib') const pumpify = require('pumpify') // from npm // calculates md5 of the secret (trimmed) function getChiperKey (secret) {} function createEncgz (secret) { const initVect = randomBytes(16) const cipherKey = getChiperKey(secret) const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() const stream = pumpify(encryptStream, gzipStream) stream.initVect = initVect return stream } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function createEncgz (secret) { } // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 25 const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 18 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 } 25 @loige 60

Slide 124

Slide 124 text

// encgz-stream.js - utility library const { createCipheriv, createDecipheriv, randomBytes, createHash } = require('crypto') const { createGzip, createGunzip } = require('zlib') const pumpify = require('pumpify') // from npm // calculates md5 of the secret (trimmed) function getChiperKey (secret) {} function createEncgz (secret) { const initVect = randomBytes(16) const cipherKey = getChiperKey(secret) const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() const stream = pumpify(encryptStream, gzipStream) stream.initVect = initVect return stream } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function createEncgz (secret) { } // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 25 const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 18 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 } 25 const stream = pumpify(encryptStream, gzipStream) // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 21 stream.initVect = initVect 22 23 return stream 24 } 25 @loige 60

Slide 125

Slide 125 text

// encgz-stream.js - utility library const { createCipheriv, createDecipheriv, randomBytes, createHash } = require('crypto') const { createGzip, createGunzip } = require('zlib') const pumpify = require('pumpify') // from npm // calculates md5 of the secret (trimmed) function getChiperKey (secret) {} function createEncgz (secret) { const initVect = randomBytes(16) const cipherKey = getChiperKey(secret) const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() const stream = pumpify(encryptStream, gzipStream) stream.initVect = initVect return stream } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 function createEncgz (secret) { } // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 25 const encryptStream = createCipheriv('aes256', cipherKey, initVect) const gzipStream = createGzip() // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 18 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 return stream 24 } 25 const stream = pumpify(encryptStream, gzipStream) // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 21 stream.initVect = initVect 22 23 return stream 24 } 25 return stream // encgz-stream.js - utility library 1 2 const { 3 createCipheriv, 4 createDecipheriv, 5 randomBytes, 6 createHash 7 } = require('crypto') 8 const { createGzip, createGunzip } = require('zlib') 9 const pumpify = require('pumpify') // from npm 10 11 // calculates md5 of the secret (trimmed) 12 function getChiperKey (secret) {} 13 14 function createEncgz (secret) { 15 const initVect = randomBytes(16) 16 const cipherKey = getChiperKey(secret) 17 const encryptStream = createCipheriv('aes256', cipherKey, initVect) 18 const gzipStream = createGzip() 19 20 const stream = pumpify(encryptStream, gzipStream) 21 stream.initVect = initVect 22 23 24 } 25 @loige 60

Slide 126

Slide 126 text

// encgz-stream.js (...continue from previous slide) function createDecgz (secret, initVect) { const cipherKey = getChiperKey(secret) const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() const stream = pumpify(gunzipStream, decryptStream) return stream } module.exports = { createEncgz, createDecgz } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @loige 61

Slide 127

Slide 127 text

// encgz-stream.js (...continue from previous slide) function createDecgz (secret, initVect) { const cipherKey = getChiperKey(secret) const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() const stream = pumpify(gunzipStream, decryptStream) return stream } module.exports = { createEncgz, createDecgz } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function createDecgz (secret, initVect) { } // encgz-stream.js (...continue from previous slide) 1 2 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 @loige 61

Slide 128

Slide 128 text

// encgz-stream.js (...continue from previous slide) function createDecgz (secret, initVect) { const cipherKey = getChiperKey(secret) const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() const stream = pumpify(gunzipStream, decryptStream) return stream } module.exports = { createEncgz, createDecgz } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function createDecgz (secret, initVect) { } // encgz-stream.js (...continue from previous slide) 1 2 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 5 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 } 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 @loige 61

Slide 129

Slide 129 text

// encgz-stream.js (...continue from previous slide) function createDecgz (secret, initVect) { const cipherKey = getChiperKey(secret) const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() const stream = pumpify(gunzipStream, decryptStream) return stream } module.exports = { createEncgz, createDecgz } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function createDecgz (secret, initVect) { } // encgz-stream.js (...continue from previous slide) 1 2 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 5 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 } 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 const stream = pumpify(gunzipStream, decryptStream) return stream // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 8 9 } 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 @loige 61

Slide 130

Slide 130 text

// encgz-stream.js (...continue from previous slide) function createDecgz (secret, initVect) { const cipherKey = getChiperKey(secret) const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() const stream = pumpify(gunzipStream, decryptStream) return stream } module.exports = { createEncgz, createDecgz } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function createDecgz (secret, initVect) { } // encgz-stream.js (...continue from previous slide) 1 2 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) const gunzipStream = createGunzip() // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 5 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 } 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 const stream = pumpify(gunzipStream, decryptStream) return stream // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 8 9 } 10 11 module.exports = { 12 createEncgz, 13 createDecgz 14 } 15 module.exports = { createEncgz, createDecgz } // encgz-stream.js (...continue from previous slide) 1 2 function createDecgz (secret, initVect) { 3 const cipherKey = getChiperKey(secret) 4 const decryptStream = createDecipheriv('aes256', cipherKey, initVect) 5 const gunzipStream = createGunzip() 6 7 const stream = pumpify(gunzipStream, decryptStream) 8 return stream 9 } 10 11 12 13 14 15 @loige 61

Slide 131

Slide 131 text

// encgz.js - CLI to encrypt and gzip (from stdin to stdout) const { pipeline } = require('stream') const { createEncgz } = require('./encgz-stream') const [, , secret] = process.argv const encgz = createEncgz(secret) console.error(`init vector: ${encgz.initVect.toString('hex')}`) pipeline( process.stdin, encgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @loige 62

Slide 132

Slide 132 text

// encgz.js - CLI to encrypt and gzip (from stdin to stdout) const { pipeline } = require('stream') const { createEncgz } = require('./encgz-stream') const [, , secret] = process.argv const encgz = createEncgz(secret) console.error(`init vector: ${encgz.initVect.toString('hex')}`) pipeline( process.stdin, encgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret] = process.argv // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 62

Slide 133

Slide 133 text

// encgz.js - CLI to encrypt and gzip (from stdin to stdout) const { pipeline } = require('stream') const { createEncgz } = require('./encgz-stream') const [, , secret] = process.argv const encgz = createEncgz(secret) console.error(`init vector: ${encgz.initVect.toString('hex')}`) pipeline( process.stdin, encgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret] = process.argv // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const encgz = createEncgz(secret) // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 62

Slide 134

Slide 134 text

// encgz.js - CLI to encrypt and gzip (from stdin to stdout) const { pipeline } = require('stream') const { createEncgz } = require('./encgz-stream') const [, , secret] = process.argv const encgz = createEncgz(secret) console.error(`init vector: ${encgz.initVect.toString('hex')}`) pipeline( process.stdin, encgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret] = process.argv // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const encgz = createEncgz(secret) // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 pipeline( ) // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 21 @loige 62

Slide 135

Slide 135 text

// encgz.js - CLI to encrypt and gzip (from stdin to stdout) const { pipeline } = require('stream') const { createEncgz } = require('./encgz-stream') const [, , secret] = process.argv const encgz = createEncgz(secret) console.error(`init vector: ${encgz.initVect.toString('hex')}`) pipeline( process.stdin, encgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret] = process.argv // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const encgz = createEncgz(secret) // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 pipeline( ) // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 11 process.stdin, 12 encgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 21 process.stdin, encgz, process.stdout, // encgz.js - CLI to encrypt and gzip (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createEncgz } = require('./encgz-stream') 4 5 const [, , secret] = process.argv 6 7 const encgz = createEncgz(secret) 8 console.error(`init vector: ${encgz.initVect.toString('hex')}`) 9 10 pipeline( 11 12 13 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 62

Slide 136

Slide 136 text

// decgz.js - CLI to gunzip and decrypt (from stdin to stdout) const { pipeline } = require('stream') const { createDecgz } = require('./encgz-stream') const [, , secret, initVect] = process.argv const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) pipeline( process.stdin, decgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @loige 63

Slide 137

Slide 137 text

// decgz.js - CLI to gunzip and decrypt (from stdin to stdout) const { pipeline } = require('stream') const { createDecgz } = require('./encgz-stream') const [, , secret, initVect] = process.argv const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) pipeline( process.stdin, decgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret, initVect] = process.argv // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 63

Slide 138

Slide 138 text

// decgz.js - CLI to gunzip and decrypt (from stdin to stdout) const { pipeline } = require('stream') const { createDecgz } = require('./encgz-stream') const [, , secret, initVect] = process.argv const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) pipeline( process.stdin, decgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret, initVect] = process.argv // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 63

Slide 139

Slide 139 text

// decgz.js - CLI to gunzip and decrypt (from stdin to stdout) const { pipeline } = require('stream') const { createDecgz } = require('./encgz-stream') const [, , secret, initVect] = process.argv const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) pipeline( process.stdin, decgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret, initVect] = process.argv // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 pipeline( ) // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 21 @loige 63

Slide 140

Slide 140 text

// decgz.js - CLI to gunzip and decrypt (from stdin to stdout) const { pipeline } = require('stream') const { createDecgz } = require('./encgz-stream') const [, , secret, initVect] = process.argv const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) pipeline( process.stdin, decgz, process.stdout, function onEnd (err) { if (err) { console.error(`Error: ${err}`) process.exit(1) } } ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const [, , secret, initVect] = process.argv // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 8 9 10 pipeline( 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 pipeline( ) // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 11 process.stdin, 12 decgz, 13 process.stdout, 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 21 process.stdin, decgz, process.stdout, // decgz.js - CLI to gunzip and decrypt (from stdin to stdout) 1 2 const { pipeline } = require('stream') 3 const { createDecgz } = require('./encgz-stream') 4 5 const [, , secret, initVect] = process.argv 6 7 const decgz = createDecgz(secret, Buffer.from(initVect, 'hex')) 8 9 10 pipeline( 11 12 13 14 function onEnd (err) { 15 if (err) { 16 console.error(`Error: ${err}`) 17 process.exit(1) 18 } 19 } 20 ) 21 @loige 63

Slide 141

Slide 141 text

@loige 64

Slide 142

Slide 142 text

readable-stream - Npm package that contains the latest version of Node.js stream library. It also makes Node.js streams compatible with the browser (can be used with Webpack and Broswserify) npm.im/readable-stream @loige * yeah, the name is misleading. The package offers all the functionalities in the official 'stream' package, not just readable streams. * 65

Slide 143

Slide 143 text

04. WRITING CUSTOM 04. WRITING CUSTOM STREAMS STREAMS @loige 66

Slide 144

Slide 144 text

@loige EmojiStream Uppercasify DOMAppend 67

Slide 145

Slide 145 text

@loige EmojiStream Uppercasify DOMAppend Lemon 67

Slide 146

Slide 146 text

@loige EmojiStream Uppercasify DOMAppend LEMON 67

Slide 147

Slide 147 text

@loige EmojiStream Uppercasify DOMAppend LEMON 67

Slide 148

Slide 148 text

@loige EmojiStream Uppercasify DOMAppend LEMON Banana 67

Slide 149

Slide 149 text

@loige EmojiStream Uppercasify DOMAppend LEMON BANANA 67

Slide 150

Slide 150 text

@loige EmojiStream Uppercasify DOMAppend LEMON BANANA 67

Slide 151

Slide 151 text

@loige EmojiStream Uppercasify DOMAppend LEMON class EmojiStream extends Readable { _read() { // ... } } BANANA 67

Slide 152

Slide 152 text

@loige EmojiStream Uppercasify DOMAppend LEMON class EmojiStream extends Readable { _read() { // ... } } class Uppercasify extends Transform { _transform( chunk, enc, done ) { // ... } } BANANA 67

Slide 153

Slide 153 text

@loige EmojiStream Uppercasify DOMAppend LEMON class EmojiStream extends Readable { _read() { // ... } } class Uppercasify extends Transform { _transform( chunk, enc, done ) { // ... } } class DOMAppend extends Writable { _write( chunk, enc, done ) { // ... } } BANANA 67

Slide 154

Slide 154 text

@loige EmojiStream Uppercasify DOMAppend LEMON class EmojiStream extends Readable { _read() { // ... } } class Uppercasify extends Transform { _transform( chunk, enc, done ) { // ... } } class DOMAppend extends Writable { _write( chunk, enc, done ) { // ... } } BANANA this.push(data) pass data to the next step 67

Slide 155

Slide 155 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @loige 68

Slide 156

Slide 156 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 @loige 68

Slide 157

Slide 157 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 class EmojiStream extends Readable { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 24 25 module.exports = EmojiStream 26 @loige 68

Slide 158

Slide 158 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 class EmojiStream extends Readable { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 24 25 module.exports = EmojiStream 26 _read () { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 23 } 24 25 module.exports = EmojiStream 26 @loige 68

Slide 159

Slide 159 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 class EmojiStream extends Readable { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 24 25 module.exports = EmojiStream 26 _read () { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 23 } 24 25 module.exports = EmojiStream 26 if (this._index >= emojis.length) { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 19 return this.push(null) 20 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 @loige 68

Slide 160

Slide 160 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 class EmojiStream extends Readable { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 24 25 module.exports = EmojiStream 26 _read () { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 23 } 24 25 module.exports = EmojiStream 26 if (this._index >= emojis.length) { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 19 return this.push(null) 20 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 return this.push(null) // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 @loige 68

Slide 161

Slide 161 text

// emoji-stream.js (custom readable stream) const { EMOJI_MAP } = require('emoji') // from npm const { Readable } = require('readable-stream') // from npm const emojis = Object.keys(EMOJI_MAP) function getEmojiDescription (index) { return EMOJI_MAP[emojis[index]][1] } function getMessage (index) { return emojis[index] + ' ' + getEmojiDescription(index) } class EmojiStream extends Readable { constructor (options) { super(options) this._index = 0 } _read () { if (this._index >= emojis.length) { return this.push(null) } return this.push(getMessage(this._index++)) } } module.exports = EmojiStream 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const { Readable } = require('readable-stream') // from npm // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 class EmojiStream extends Readable { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 24 25 module.exports = EmojiStream 26 _read () { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 return this.push(getMessage(this._index++)) 22 23 } 24 25 module.exports = EmojiStream 26 if (this._index >= emojis.length) { } // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 19 return this.push(null) 20 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 return this.push(null) // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 20 } 21 return this.push(getMessage(this._index++)) 22 } 23 } 24 25 module.exports = EmojiStream 26 return this.push(getMessage(this._index++)) // emoji-stream.js (custom readable stream) 1 const { EMOJI_MAP } = require('emoji') // from npm 2 const { Readable } = require('readable-stream') // from npm 3 const emojis = Object.keys(EMOJI_MAP) 4 function getEmojiDescription (index) { 5 return EMOJI_MAP[emojis[index]][1] 6 } 7 function getMessage (index) { 8 return emojis[index] + ' ' + getEmojiDescription(index) 9 } 10 11 class EmojiStream extends Readable { 12 constructor (options) { 13 super(options) 14 this._index = 0 15 } 16 17 _read () { 18 if (this._index >= emojis.length) { 19 return this.push(null) 20 } 21 22 } 23 } 24 25 module.exports = EmojiStream 26 @loige 68

Slide 162

Slide 162 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 @loige 69

Slide 163

Slide 163 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 const { Transform } = require('readable-stream') // uppercasify.js (custom transform stream) 1 2 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 @loige 69

Slide 164

Slide 164 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 const { Transform } = require('readable-stream') // uppercasify.js (custom transform stream) 1 2 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 class Uppercasify extends Transform { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 10 11 module.exports = Uppercasify 12 @loige 69

Slide 165

Slide 165 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 const { Transform } = require('readable-stream') // uppercasify.js (custom transform stream) 1 2 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 class Uppercasify extends Transform { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 10 11 module.exports = Uppercasify 12 _transform (chunk, encoding, done) { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 9 } 10 11 module.exports = Uppercasify 12 @loige 69

Slide 166

Slide 166 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 const { Transform } = require('readable-stream') // uppercasify.js (custom transform stream) 1 2 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 class Uppercasify extends Transform { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 10 11 module.exports = Uppercasify 12 _transform (chunk, encoding, done) { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 9 } 10 11 module.exports = Uppercasify 12 this.push(chunk.toString().toUpperCase()) // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 @loige 69

Slide 167

Slide 167 text

// uppercasify.js (custom transform stream) const { Transform } = require('readable-stream') class Uppercasify extends Transform { _transform (chunk, encoding, done) { this.push(chunk.toString().toUpperCase()) done() } } module.exports = Uppercasify 1 2 3 4 5 6 7 8 9 10 11 12 const { Transform } = require('readable-stream') // uppercasify.js (custom transform stream) 1 2 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 class Uppercasify extends Transform { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 } 9 10 11 module.exports = Uppercasify 12 _transform (chunk, encoding, done) { } // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 6 this.push(chunk.toString().toUpperCase()) 7 done() 8 9 } 10 11 module.exports = Uppercasify 12 this.push(chunk.toString().toUpperCase()) // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 7 done() 8 } 9 } 10 11 module.exports = Uppercasify 12 done() // uppercasify.js (custom transform stream) 1 2 const { Transform } = require('readable-stream') 3 4 class Uppercasify extends Transform { 5 _transform (chunk, encoding, done) { 6 this.push(chunk.toString().toUpperCase()) 7 8 } 9 } 10 11 module.exports = Uppercasify 12 @loige 69

Slide 168

Slide 168 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @loige 70

Slide 169

Slide 169 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { Writable } = require('readable-stream') // dom-append.js (custom writable stream) 1 2 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 @loige 70

Slide 170

Slide 170 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { Writable } = require('readable-stream') // dom-append.js (custom writable stream) 1 2 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 class DOMAppend extends Writable { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 14 15 module.exports = DOMAppend 16 @loige 70

Slide 171

Slide 171 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { Writable } = require('readable-stream') // dom-append.js (custom writable stream) 1 2 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 class DOMAppend extends Writable { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 14 15 module.exports = DOMAppend 16 _write (chunk, encoding, done) { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 13 } 14 15 module.exports = DOMAppend 16 @loige 70

Slide 172

Slide 172 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { Writable } = require('readable-stream') // dom-append.js (custom writable stream) 1 2 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 class DOMAppend extends Writable { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 14 15 module.exports = DOMAppend 16 _write (chunk, encoding, done) { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 13 } 14 15 module.exports = DOMAppend 16 const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 8 9 10 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 @loige 70

Slide 173

Slide 173 text

// dom-append.js (custom writable stream) const { Writable } = require('readable-stream') class DOMAppend extends Writable { _write (chunk, encoding, done) { const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) done() } } module.exports = DOMAppend 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const { Writable } = require('readable-stream') // dom-append.js (custom writable stream) 1 2 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 class DOMAppend extends Writable { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 } 13 14 15 module.exports = DOMAppend 16 _write (chunk, encoding, done) { } // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 done() 12 13 } 14 15 module.exports = DOMAppend 16 const elem = document.createElement('li') const content = document.createTextNode(chunk.toString()) elem.appendChild(content) document.getElementById('list').appendChild(elem) // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 8 9 10 11 done() 12 } 13 } 14 15 module.exports = DOMAppend 16 done() // dom-append.js (custom writable stream) 1 2 const { Writable } = require('readable-stream') 3 4 class DOMAppend extends Writable { 5 6 _write (chunk, encoding, done) { 7 const elem = document.createElement('li') 8 const content = document.createTextNode(chunk.toString()) 9 elem.appendChild(content) 10 document.getElementById('list').appendChild(elem) 11 12 } 13 } 14 15 module.exports = DOMAppend 16 @loige 70

Slide 174

Slide 174 text

05. STREAMS IN THE 05. STREAMS IN THE BROWSER BROWSER @loige 71

Slide 175

Slide 175 text

// browser/app.js const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() emoji .pipe(uppercasify) .pipe(append) 1 2 3 4 5 6 7 8 9 10 11 12 13 @loige 72

Slide 176

Slide 176 text

// browser/app.js const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() emoji .pipe(uppercasify) .pipe(append) 1 2 3 4 5 6 7 8 9 10 11 12 13 const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') // browser/app.js 1 2 3 4 5 6 const emoji = new EmojiStream() 7 const uppercasify = new Uppercasify() 8 const append = new DOMAppend() 9 10 emoji 11 .pipe(uppercasify) 12 .pipe(append) 13 @loige 72

Slide 177

Slide 177 text

// browser/app.js const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() emoji .pipe(uppercasify) .pipe(append) 1 2 3 4 5 6 7 8 9 10 11 12 13 const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') // browser/app.js 1 2 3 4 5 6 const emoji = new EmojiStream() 7 const uppercasify = new Uppercasify() 8 const append = new DOMAppend() 9 10 emoji 11 .pipe(uppercasify) 12 .pipe(append) 13 const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() // browser/app.js 1 2 const EmojiStream = require('../emoji-stream') 3 const Uppercasify = require('../uppercasify') 4 const DOMAppend = require('../dom-append') 5 6 7 8 9 10 emoji 11 .pipe(uppercasify) 12 .pipe(append) 13 @loige 72

Slide 178

Slide 178 text

// browser/app.js const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() emoji .pipe(uppercasify) .pipe(append) 1 2 3 4 5 6 7 8 9 10 11 12 13 const EmojiStream = require('../emoji-stream') const Uppercasify = require('../uppercasify') const DOMAppend = require('../dom-append') // browser/app.js 1 2 3 4 5 6 const emoji = new EmojiStream() 7 const uppercasify = new Uppercasify() 8 const append = new DOMAppend() 9 10 emoji 11 .pipe(uppercasify) 12 .pipe(append) 13 const emoji = new EmojiStream() const uppercasify = new Uppercasify() const append = new DOMAppend() // browser/app.js 1 2 const EmojiStream = require('../emoji-stream') 3 const Uppercasify = require('../uppercasify') 4 const DOMAppend = require('../dom-append') 5 6 7 8 9 10 emoji 11 .pipe(uppercasify) 12 .pipe(append) 13 emoji .pipe(uppercasify) .pipe(append) // browser/app.js 1 2 const EmojiStream = require('../emoji-stream') 3 const Uppercasify = require('../uppercasify') 4 const DOMAppend = require('../dom-append') 5 6 const emoji = new EmojiStream() 7 const uppercasify = new Uppercasify() 8 const append = new DOMAppend() 9 10 11 12 13 @loige 72

Slide 179

Slide 179 text

npm i --save-dev webpack webpack-cli node_modules/.bin/webpack src/browser/app.js # creates dist/main.js mv dist/main.js src/browser/app-bundle.js @loige Let's use webpack to build this app for the browser 73

Slide 180

Slide 180 text

Streams in the browser!
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @loige Finally let's create an index.html 74

    Slide 181

    Slide 181 text

    Streams in the browser!
      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
        1 2 3 4 8 Streams in the browser! 9 10 11 12 13 14 15 @loige Finally let's create an index.html 74

        Slide 182

        Slide 182 text

        Streams in the browser!
          1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
            1 2 3 4 8 Streams in the browser! 9 10 11 12 13 14 15 1 2 3 4 8 Streams in the browser! 9 10 11
              12 13 14 15 @loige Finally let's create an index.html 74

              Slide 183

              Slide 183 text

              @loige 75

              Slide 184

              Slide 184 text

              @loige 75

              Slide 185

              Slide 185 text

              06. CLOSING 06. CLOSING @loige 76

              Slide 186

              Slide 186 text

              Streams have low memory footprint Process data as soon as it's available Composition through pipelines Streams are abstractions: Readable = Input Transform = Business Logic Writable = Output @loige TLDR; TLDR; 77

              Slide 187

              Slide 187 text

              IF YOU WANT TO LEARN (EVEN) MOAR IF YOU WANT TO LEARN (EVEN) MOAR ABOUT STREAMS... ABOUT STREAMS... nodejs.org/api/stream.html github.com/substack/stream-handbook @loige 78

              Slide 188

              Slide 188 text

              IF YOU ARE NOT CONVINCED YET... IF YOU ARE NOT CONVINCED YET... @loige curl parrot.live 79

              Slide 189

              Slide 189 text

              @loige github.com/hugomd/parrot.live Check out the codebase 80

              Slide 190

              Slide 190 text

              @loige 81

              Slide 191

              Slide 191 text

              @loige ДЯКУЮ ДЯКУЮ! ! loige.link/streams-kyiv We are hiring, talk to me! :) 82

              Slide 192

              Slide 192 text

              CREDITS CREDITS Cover picture by on for the amazing St. Patrick emoji art The internet for the memes! :D Johny Goerend Unsplash emojiart.org SPECIAL THANKS SPECIAL THANKS , , , , , @StefanoAbalsamo @mariocasciaro @machine_person @Podgeypoos79 @katavic_d @UrsoLuca @loige 83