Slide 1

Slide 1 text

ʮ4USFBNΛͪΌΜͱཧղ͢Δʯ

Slide 2

Slide 2 text

4BVOB4QB)FBMUI"EWJTFS⽂ Takeshi Kato Frontend Developer in

Slide 3

Slide 3 text

ʮ4USFBNΛ੍͢Δ΋ͷ͸ɺ/PEFKTΛ੍͢ʯ IUUQKYDLIBUFOBCMPHDPNFOUSZ

Slide 4

Slide 4 text

ʮ4USFBNT"1*ʯ TJODF0DU 4USFBNT˜8)"58( "QQMF (PPHMF .P[JMMB .JDSPTPGU -JDFOTFEVOEFS$$#:

Slide 5

Slide 5 text

ʮ4USFBNT"1*ʯ TJODF0DU

Slide 6

Slide 6 text

4USFBNʁ ετϦʔϜʢӳTUSFBNʣͱ͸ɺ ࿈ଓͨ͠σʔλΛʮྲྀΕΔ΋ͷʯͱͯ͠ଊ͑ɺ ͦͷσʔλͷೖग़ྗ͋Δ͍͸ૹड৴Λѻ͏͜ͱͰ͋Γɺ ·ͨͦͷૢ࡞ͷͨΊͷந৅σʔλܕΛࢦ͢ɻ ग़యϑϦʔඦՊࣄయʰ΢ΟΩϖσΟΞʢ8JLJQFEJBʣʱ

Slide 7

Slide 7 text

αʔό ॲཧ ඳը αʔό ॲཧ ඳը XJUI4USFBN XJUIPVU4USFBN

Slide 8

Slide 8 text

αʔό αʔό XJUI4USFBN XJUIPVU4USFBN ॲཧ ඳը ॲཧ ඳը

Slide 9

Slide 9 text

3FBEBCMF 4USFBN 5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN ʮ4USFBNT"1*ʯ

Slide 10

Slide 10 text

5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN 3FBEBCMF 4USFBN

Slide 11

Slide 11 text

3FBEBCMF4USFBNʢಡΈࠐΈՄೳͳετϦʔϜʣ 2VF $IVOL 6OEFSMZJOH4PVSDF %BUB ɾ6OEFSMZJOH4PVSDF ɹσʔλͷݯͱͳΔΦϒδΣΫτɻը૾΍ಈըͳͲͷϝσΟΞ͚ͩͰͳ͘ ɹςΩετɺ਺஋ͳͲ΋ѻ͑Δɻ ɾ\3FBEBCMF4USFBN%FGBVMU$POUSPMMFS^ ɹετϦʔϜͷঢ়ଶ΍಺෦Ωϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻᶃͷૢ࡞Λ୲౰͢Δɻ ɾ\3FBEBCMF4USFBN%FGBVMU3FBEFS^ ɹετϦʔϜ͔ΒνϟϯΫΛಡΈऔΔΫϥεɻᶄͷૢ࡞Λ୲౰͢Δɻ ᶃ ᶄ

Slide 12

Slide 12 text

const stream = new ReadableStream( { // ͜ͷΦϒδΣΫτ͕Underlying Source start(controller) { // ReadableStreamDefaultController controller.enqueue(chunk); // QueʹChunkΛొ࿥͢Δ }, pull(controller) {}, cancel(reason) {} } ); const reader = stream.getReader(); // ReadableStreamDefaultReader reader.read().then(function readProcess({done, value}) { if (done) { return; } result += value; reader.read().then(readProcess); });

Slide 13

Slide 13 text

const stream = new ReadableStream( { // ͜ͷΦϒδΣΫτ͕Underlying Source start(controller) { // ReadableStreamDefaultController controller.enqueue(chunk); // QueʹChunkΛొ࿥͢Δ }, pull(controller) {}, cancel(reason) {} } ); const reader = stream.getReader(); // ReadableStreamDefaultReader reader.read().then(function readProcess({done, value}) { if (done) { return; } result += value; reader.read().then(readProcess); });

Slide 14

Slide 14 text

const stream = new ReadableStream( { // ͜ͷΦϒδΣΫτ͕Underlying Source start(controller) { // ReadableStreamDefaultController controller.enqueue(chunk); // QueʹChunkΛొ࿥͢Δ }, pull(controller) {}, cancel(reason) {} } ); const reader = stream.getReader(); // ReadableStreamDefaultReader reader.read().then(function readProcess({done, value}) { if (done) { return; } result += value; reader.read().then(readProcess); });

Slide 15

Slide 15 text

const stream = new ReadableStream( { // ͜ͷΦϒδΣΫτ͕Underlying Source start(controller) { // ReadableStreamDefaultController controller.enqueue(chunk); // QueʹChunkΛొ࿥͢Δ }, pull(controller) {}, cancel(reason) {} } ); const reader = stream.getReader(); // ReadableStreamDefaultReader reader.read().then(function readProcess({done, value}) { if (done) { return; } result += value; reader.read().then(readProcess); });

Slide 16

Slide 16 text

$BTFʮ4USFBNJOH3FTQPOTFʯ

Slide 17

Slide 17 text

'FUDI"1*࣮ߦޙʹड͚औΕΔ3FTQPOTFͷ#PEZ ͸ʮ3FBEBCMF4USFBNʯ ``` fetch(url).then(response => response.body).then(readableStream => { // do something }); ```

Slide 18

Slide 18 text

4FSWJDF8PSLFSͰϦΫΤετΛΠϯλʔηϓτͯ͠ɺ 4USFBNΛ3FTQPOTFͱͯ͠ฦ͢

Slide 19

Slide 19 text

4BNQMF

Slide 20

Slide 20 text

self.addEventListener('fetch', event => { var stream = new ReadableStream({ async start(controller) { let html = await caches.match(‘cache.html').then(res => res.text()); const encoder = new TextEncoder(); let pos = 0, chunkSize = 1; function push() { if (pos >= html.length) { controller.close(); return; } controller.enqueue(encoder.encode(html.slice(pos, pos + chunkSize))); pos += chunkSize; setTimeout(push, 5); } push(); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); }); ࢀߟ: https://jakearchibald.com/2016/streams-ftw/#creating-one-stream-from-multiple-sources-to-supercharge-page-render-times

Slide 21

Slide 21 text

self.addEventListener('fetch', event => { var stream = new ReadableStream({ async start(controller) { let html = await caches.match(‘cache.html').then(res => res.text()); const encoder = new TextEncoder(); let pos = 0, chunkSize = 1; function push() { if (pos >= html.length) { controller.close(); return; } controller.enqueue(encoder.encode(html.slice(pos, pos + chunkSize))); pos += chunkSize; setTimeout(push, 5); } push(); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); }); ࢀߟ: https://jakearchibald.com/2016/streams-ftw/#creating-one-stream-from-multiple-sources-to-supercharge-page-render-times

Slide 22

Slide 22 text

self.addEventListener('fetch', event => { var stream = new ReadableStream({ async start(controller) { let html = await caches.match(‘cache.html').then(res => res.text()); const encoder = new TextEncoder(); let pos = 0, chunkSize = 1; function push() { if (pos >= html.length) { controller.close(); return; } controller.enqueue(encoder.encode(html.slice(pos, pos + chunkSize))); pos += chunkSize; setTimeout(push, 5); } push(); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); }); ࢀߟ: https://jakearchibald.com/2016/streams-ftw/#creating-one-stream-from-multiple-sources-to-supercharge-page-render-times event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html’} }));

Slide 23

Slide 23 text

``` caches.match(request).then(res => res.body).then(readableStream => { // do something }); ``` $BDIF"1*࣮ߦޙʹड͚औΕΔ3FTQPOTFͷ#PEZ ΋ʮ3FBEBCMF4USFBNʯ

Slide 24

Slide 24 text

ϔομʔʢDBDIFʣ ίϯςϯπʢGFUDIʣ ϑολʔʢDBDIFʣ ͷΑ͏ͳ͜ͱ΋Ͱ͖Δ

Slide 25

Slide 25 text

var stream = new ReadableStream({ start(controller) { const header = caches.match('./inc/header.html'); const contents = fetch(event.request.url); const footer = caches.match('./inc/footer.html'); function push(stream) { const reader = stream.getReader(); function read({done, value}) { if (done) return; controller.enqueue(value); return reader.read().then(read); } return reader.read().then(read); } header.then(response => push(response.body)).then(() => contents) .then(response => push(response.body)).then(() => footer) .then(response => push(response.body)).then(() => controller.close()); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); ࢀߟ: https://gist.github.com/jakearchibald/64e26e7a1d9b06b3fa3ec0383f2b1f91

Slide 26

Slide 26 text

var stream = new ReadableStream({ start(controller) { const header = caches.match('./inc/header.html'); const contents = fetch(event.request.url); const footer = caches.match('./inc/footer.html'); function push(stream) { const reader = stream.getReader(); function read({done, value}) { if (done) return; controller.enqueue(value); return reader.read().then(read); } return reader.read().then(read); } header.then(response => push(response.body)).then(() => contents) .then(response => push(response.body)).then(() => footer) .then(response => push(response.body)).then(() => controller.close()); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); ࢀߟ: https://gist.github.com/jakearchibald/64e26e7a1d9b06b3fa3ec0383f2b1f91

Slide 27

Slide 27 text

var stream = new ReadableStream({ start(controller) { const header = caches.match('./inc/header.html'); const contents = fetch(event.request.url); const footer = caches.match('./inc/footer.html'); function push(stream) { const reader = stream.getReader(); function read({done, value}) { if (done) return; controller.enqueue(value); return reader.read().then(read); } return reader.read().then(read); } header.then(response => push(response.body)).then(() => contents) .then(response => push(response.body)).then(() => footer) .then(response => push(response.body)).then(() => controller.close()); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); ࢀߟ: https://gist.github.com/jakearchibald/64e26e7a1d9b06b3fa3ec0383f2b1f91

Slide 28

Slide 28 text

var stream = new ReadableStream({ start(controller) { const header = caches.match('./inc/header.html'); const contents = fetch(event.request.url); const footer = caches.match('./inc/footer.html'); function push(stream) { const reader = stream.getReader(); function read({done, value}) { if (done) return; controller.enqueue(value); return reader.read().then(read); } return reader.read().then(read); } header.then(response => push(response.body)).then(() => contents) .then(response => push(response.body)).then(() => footer) .then(response => push(response.body)).then(() => controller.close()); } }); event.respondWith(new Response(stream, { headers: {'Content-Type': ‘text/html'} })); ࢀߟ: https://gist.github.com/jakearchibald/64e26e7a1d9b06b3fa3ec0383f2b1f91

Slide 29

Slide 29 text

3FBEBCMF4USFBNΛ࢖͏ͱ σʔλΛ෼ׂͯ͠গͣͭ͠ ಡΈࠐΉ͜ͱ͕Ͱ͖Δ

Slide 30

Slide 30 text

5SBOTGPSN 4USFBN 3FBEBCMF 4USFBN 8SJUBCMF 4USFBN

Slide 31

Slide 31 text

8SJUBCMF4USFBNʢॻ͖ࠐΈՄೳͳετϦʔϜʣ 2VF 6OEFSMZJOH4JOL /FX%BUB ɾ\6OEFSMZJOH4JOL^ ɹΩϡʔ͔ΒνϟϯΫΛड͚औͬͯॻ͖ࠐΈΛߦ͏ΦϒδΣΫτɻ ɾ\8SJUBCMF4USFBN%FGBVMU8SJUFS^ ɹ8SJUBCMF4USFBNʹ௚઀νϟϯΫΛॻ͖ࠐΉ͜ͱ͕Ͱ͖ΔΫϥεɻ ɹᶃͷૢ࡞Λ୲౰͢Δɻ ɾ\8SJUBCMF4USFBN%FGBVMU$POUSPMMFS^ ɹετϦʔϜͷঢ়ଶ΍಺෦Ωϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻᶄͷૢ࡞Λ୲౰͢Δɻ ᶄ ᶃ

Slide 32

Slide 32 text

const stream = new WritableStream( { // ͜ͷΦϒδΣΫτ͕UnderlyingSink start(controller) {}, write(chunk, controller) { // WritableStreamDefaultController output.value = chunk; // Hello }, close() {}, abort(reason) {} } ); const writer = stream.getWriter(); // WritableStreamDefaultWriter writer.ready.then(() => writer.write('hello')) .then(() => writer.write('world')) .then(() => writer.close()) .then(() => console.log('close writer.'))

Slide 33

Slide 33 text

const stream = new WritableStream( { // ͜ͷΦϒδΣΫτ͕UnderlyingSink start(controller) {}, write(chunk, controller) { // WritableStreamDefaultController output.value = chunk; // Hello }, close() {}, abort(reason) {} } ); const writer = stream.getWriter(); // WritableStreamDefaultWriter writer.ready.then(() => writer.write('hello')) .then(() => writer.write('world')) .then(() => writer.close()) .then(() => console.log('close writer.'))

Slide 34

Slide 34 text

const stream = new WritableStream( { // ͜ͷΦϒδΣΫτ͕UnderlyingSink start(controller) {}, write(chunk, controller) { // WritableStreamDefaultController output.value = chunk; // Hello }, close() {}, abort(reason) {} } ); const writer = stream.getWriter(); // WritableStreamDefaultWriter writer.ready.then(() => writer.write('hello')) .then(() => writer.write('world')) .then(() => writer.close()) .then(() => console.log('close writer.'))

Slide 35

Slide 35 text

const stream = new WritableStream( { // ͜ͷΦϒδΣΫτ͕UnderlyingSink start(controller) {}, write(chunk, controller) { // WritableStreamDefaultController output.value = chunk; // Hello }, close() {}, abort(reason) {} } ); const writer = stream.getWriter(); // WritableStreamDefaultWriter writer.ready.then(() => writer.write('hello')) .then(() => writer.write('world')) .then(() => writer.close()) .then(() => console.log('close writer.'))

Slide 36

Slide 36 text

3FBEBCMF 4USFBN 8SJUBCMF 4USFBN QJQF5P

Slide 37

Slide 37 text

$BTFʮ/BUJWF'JMF4ZTUFNʯ ʮϑΝΠϧΛ'FUDIͯ͠ɺυϥΠϒʹ௚઀ॻ͖ࠐΈʯ

Slide 38

Slide 38 text

4BNQMF

Slide 39

Slide 39 text

fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter = await handle.createWriter(); // handle͸NativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ let offset = 0; const writableStream = new WritableStream({ start() { return fileWriter.truncate(0); }, write(chunk, controller) { return new Promise(async (resolve, reject) => { try { await fileWriter.write(offset, chunk); offset += chunk.length; resolve(); } catch(err) { controller.error(err); reject(err); } }); }, close() { fileWriter.close(); } }); readableStream.pipeTo(writableStream); })

Slide 40

Slide 40 text

fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter = await handle.createWriter(); // handle͸NativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ let offset = 0; const writableStream = new WritableStream({ start() { return fileWriter.truncate(0); }, write(chunk, controller) { return new Promise(async (resolve, reject) => { try { await fileWriter.write(offset, chunk); offset += chunk.length; resolve(); } catch(err) { controller.error(err); reject(err); } }); }, close() { fileWriter.close(); } }); readableStream.pipeTo(writableStream); })

Slide 41

Slide 41 text

fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter = await handle.createWriter(); // handle͸NativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ let offset = 0; const writableStream = new WritableStream({ start() { return fileWriter.truncate(0); }, write(chunk, controller) { return new Promise(async (resolve, reject) => { try { await fileWriter.write(offset, chunk); offset += chunk.length; resolve(); } catch(err) { controller.error(err); reject(err); } }); }, close() { fileWriter.close(); } }); readableStream.pipeTo(writableStream); })

Slide 42

Slide 42 text

fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter = await handle.createWriter(); // handle͸NativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ let offset = 0; const writableStream = new WritableStream({ start() { return fileWriter.truncate(0); }, write(chunk, controller) { return new Promise(async (resolve, reject) => { try { await fileWriter.write(offset, chunk); offset += chunk.length; resolve(); } catch(err) { controller.error(err); reject(err); } }); }, close() { fileWriter.close(); } }); readableStream.pipeTo(writableStream); })

Slide 43

Slide 43 text

/BUJWF'JMF4ZTUFN Y 4USFBNT"1* IUUQTHJUIVCDPNXJDHOBUJWFpMFTZTUFNJTTVFT 4USFBNΛ࢖༻ͨ͠ॻ͖ࠐΈͷ࣮૷͕ʢଟ෼ʣਐΜͰ͍Δ

Slide 44

Slide 44 text

8SJUBCMF4USFBNΛ࢖͏ͱ ෼ׂ͞ΕͨσʔλΛ Ұͭͣͭɺॱ൪ʹ ॻ͖ࠐΉ͜ͱ͕Ͱ͖Δ

Slide 45

Slide 45 text

3FBEBCMF 4USFBN 8SJUBCMF 4USFBN 5SBOTGPSN 4USFBN

Slide 46

Slide 46 text

5SBOTGPSN4USFBNɹʢม׵ετϦʔϜʣ 8SJUBCMF4USFBN 5SBOTGPSNFS 3FBEBCMF4USFBN ɾ\XSJUBCMF SFBEBCMF^ ɹ8SJUBCMF4USFBNͱ3FBEBCMF4USFBNΛ಺แ͍ͯ͠Δɻ ɾ\5SBOTGPSNFS^ ɹ8SJUBCMF4USFBN͔Β$IVOLΛड͚औͬͯɺม׵ॲཧΛߦ͏ΦϒδΣΫτɻ ɾ\5SBOTGPSN4USFBN%FGBVMU$POUSPMMFS^ ɹ8SJUBCMFɺ3FBEBCMF4USFBNͷঢ়ଶ΍Ωϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻ

Slide 47

Slide 47 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 48

Slide 48 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 49

Slide 49 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 50

Slide 50 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 51

Slide 51 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 52

Slide 52 text

3FBEBCMF 4USFBN 5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN QJQF5ISPVHI 3&563/3FBEBCMF4USFBN QJQF5P 3&563/1SPNJTF

Slide 53

Slide 53 text

5FYU&ODPEFS4USFBNɾ5FYU%FDPEFS4USFBN GSPN&ODPEJOH"1*

Slide 54

Slide 54 text

const transformStream = new TransformStream( { // ͜ͷΦϒδΣΫτ͕Transformer start(controller) {}, transform(chunk, controller) { // Τϯίʔυ͞ΕͨChunkΛσίʔυͯ͠Ωϡʔʹొ࿥͢Δ controller.enqueue(new TextDecoder().decode(chunk)); }, flush(controller) { // Writable StreamʹΑΔશͯͷॻ͖ࠐΈ͕ऴΘΓɺ // Writable Stream͕Ϋϩʔζ͠Α͏ͱ͍ͯ͠Δ࣌ʹݺͼग़͞ΕΔ } } ); const {readable, writable} = transformStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World });

Slide 55

Slide 55 text

const textDecoderStream = new TextDecoderStream('utf-8'); const {readable, writable} = textDecoderStream; writable.getWriter().write( new Uint8Array([104,101,108,108,111,32,119,111,114,108,100]) ); readable.getReader().read().then(({done, value}) => { console.log(value); // Hello World }); ˞ͨͩ͠ɺ5SBOTGFS4USFBNͷܧঝͰ͸ͳ͍ɻʢಉ͡*'Λඋ͍͑ͯΔ͚ͩʣ ࢀߟIUUQTHJUIVCDPNXIBUXHFODPEJOHJTTVFT

Slide 56

Slide 56 text

$BTFʮ຋༁ʯ

Slide 57

Slide 57 text

4BNQMF

Slide 58

Slide 58 text

function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); } const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } }); input.addEventListener('change', function () { const stream = input.files[0].stream(); const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); });

Slide 59

Slide 59 text

function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); } const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } }); input.addEventListener('change', function () { const stream = input.files[0].stream(); const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); }); function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); }

Slide 60

Slide 60 text

function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); } const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } }); input.addEventListener('change', function () { const stream = input.files[0].stream(); const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); }); const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } });

Slide 61

Slide 61 text

function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); } const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } }); input.addEventListener('change', function () { const stream = input.files[0].stream(); const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); }); input.addEventListener('change', function () { // input͸[type=“file”]ͷinputཁૉ const stream = input.files[0].stream(); // fileΦϒδΣΫτ͸stream()ͰReadableStream͕औಘͰ͖Δ const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream(‘utf-8')) .pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream(‘utf-8')) .pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); });

Slide 62

Slide 62 text

function md2HTMLFactory() { return new TransformStream({ transform(chunk, controller) { controller.enqueue(marked(chunk)); } }); } const translateStream = new TransformStream({ transform(chunk, controller) { return fetch(`https://translation.googleapis.com/language/translate/v2/?key={API_KEY}`, { method: 'POST', body: JSON.stringify({ q: chunk, target: 'en', format: 'html' }) }).then(res => res.json()).then(res => { controller.enqueue(res.data.translations[0].translatedText); }); } }); input.addEventListener('change', function () { const stream = input.files[0].stream(); const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream('utf-8')).pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); }); input.addEventListener('change', function () { // input͸[type=“file”]ͷinputཁૉ const stream = input.files[0].stream(); // fileΦϒδΣΫτ͸stream()ͰReadableStream͕औಘͰ͖Δ const [org, willBeTranslated] = stream.tee(); Promise.all([ org.pipeThrough(new TextDecoderStream(‘utf-8')) .pipeThrough(md2HTMLFactory()) .pipeTo(originalWriter), willBeTranslated.pipeThrough(new TextDecoderStream(‘utf-8')) .pipeThrough(md2HTMLFactory()) .pipeThrough(translateStream) .pipeTo(translatedWriter) ]).then(() => console.log('complete')); });

Slide 63

Slide 63 text

3FBEBCMF4USFBNɾ8SJUBCMF4USFBNΛར༻͢ΔΞΫςΟϒͳಡΈऔ Γػͱॻ͖ࠐΈػ͕͋Δؒɺ֤ετϦʔϜ͸ʮϩοΫʯ͞Εɺղ์͞ΕΔ ·Ͱଞ͔ΒετϦʔϜར༻Ͱ͖ͳ͘ͳΔɻ const readable = new ReadableStream(); const writable = new WritableStream(); const reader = readable.getReader(); const writer = writable.getWriter(); console.log(readable.locked); // true console.log(writable.locked); // true readable.getReader(); // error! MPDLFEͱUFF

Slide 64

Slide 64 text

ಉ͡3FBEBCMFετϦʔϜΛ࢖͍͍ͨ৔߹͸ೋຢԽʢUFFʣ͢Δඞཁ͕͋ Γ·͢ɻ ྫʣJOQVUͰΞοϓϩʔυͨ͠ϑΝΠϧΛTUSFBNͰѻ͏ྫ MPDLFEͱUFF input.addEventListener('change', function () { const stream = input.files[0].stream(); // ͓͓΋ͱΛڞ༗ͨ͠2ͭͷStreamͷ഑ྻ͕ಘΒΕΔ const [org, translated] = stream.tee(); … });

Slide 65

Slide 65 text

5SBOTGPSN4USFBNΛ࢖͏ͱ νϟϯΫΛྲྀΕΔΑ͏ʹม׵͠ɺ ͞ΒʹಡΈࠐΈ௚͢͜ͱ͕Ͱ͖Δ

Slide 66

Slide 66 text

3FBEBCMF 4USFBN 8SJUBCMF 4USFBN 5SBOTGPSN 4USFBN

Slide 67

Slide 67 text

ͦͷଞͷ֓೦ͱ"1* ɾഎѹʢ#BDL1SFTTVSFʣ ɾ1VTI4PVSDFͱ1VMM4PVSDF ɾ2VFVJOH4USBUFHZ

Slide 68

Slide 68 text

3FBEBCMF 4USFBN 8SJUBCMF 4USFBN #BDL1SFTTVSFͱ͸ ޙΖ͕٧·ͬͨʢΩϡʔʹۭ͖͕ͳ͘ͳͬͨʣ࣌ʹɺ

Slide 69

Slide 69 text

8SJUBCMF 4USFBN 3FBEBCMF 4USFBN #BDL1SFTTVSFͱ͸ ޙΖ͕٧·ͬͨʢΩϡʔʹۭ͖͕ͳ͘ͳͬͨʣ࣌ʹɺ ύΠϓΛ௨ͯ͠લͷετϦʔϜʹ௨஌͢Δ

Slide 70

Slide 70 text

ɾ1VTI4PVSDF ɹ4PVSDFଆ͔ΒࣗൃతʹFORVFVF͢ΔλΠϓ FH4PDLFU ɾ1VMM4PVSDF ɹϦΫΤετʹԠͯ͡FORVFVF͢ΔλΠϓ FHϑΝΠϧϋϯυϧ ɹ 6OEFSMZJOH4PVSDFͷͭͷλΠϓ

Slide 71

Slide 71 text

1VTI4PVSDF new ReadableStream({ start(controller) { socket.addEventListener('message', (e) => { controller.enqueue(e.data); }); } }); 1VMM4PVSDF new ReadableStream({ pull(controller) { controller.enqueue(Math.random()); } }); ˞TUBSUΛ࢖͍ͬͯΕ͹1VTIɺQVMMΛ࢖͍ͬͯΕ͹1VMMͱ͍͏Θ͚Ͱ͸͋Γ·ͤΜɻ

Slide 72

Slide 72 text

1VTI4PVSDF new ReadableStream({ start(controller) { socket.addEventListener('message', (e) => { controller.enqueue(e.data); }); } }); 1VMM4PVSDF new ReadableStream({ pull(controller) { controller.enqueue(Math.random()); } }); QVMMϝιου͸ Ωϡʔʹۭ͖͕ͳ͘ͳΔ·Ͱ ࣮ߦ͞ΕΔ

Slide 73

Slide 73 text

1VTI4PVSDF new ReadableStream({ start(controller) { socket.addEventListener('message', (e) => { controller.enqueue(e.data); }); } }); 1VMM4PVSDF new ReadableStream({ pull(controller) { controller.enqueue(Math.random()); } }); QVMMϝιου͸ Ωϡʔʹۭ͖ʢʁʣ͕ͳ͘ͳΔ·Ͱ ࣮ߦ͞ΕΔ

Slide 74

Slide 74 text

֤ετϦʔϜ͕࣋ͭΩϡʔʹอ࣋Ͱ͖ΔαΠζͱ࠷େ਺ʢͭ·Γۭ͖ʣΛ ܾΊΔΦϒδΣΫτɻΦϒδΣΫτ͸ҎԼͷϓϩύςΟΛ࣋ͭɻ ɾIJHI8BUFS.BSLOVNCFS ɹετϦʔϜͷݶքਫҐʢΩϟύγςΟʣΛࢦఆ͢Δɻɹ )8.ʢΩϡʔʹొ࿥͞Ε͍ͯΔνϟϯΫͷ߹ܭαΠζʣ ɾTJ[F DIVOL OVNCFS ɹԿΛ΋ͬͯΩϡʔͷαΠζΛදݱ͢Δ͔Λܾఆ͢Δؔ਺ɻ 2VFVJOH4USBUFHZ

Slide 75

Slide 75 text

ྫʣDIVOLΛจࣈྻͱͯ͠ड͚औΔ͜ͱΛ૝ఆͨ͠৔߹ɺ ɹ͜ͷ4USFBN͸߹ܭจࣈ·Ͱ͔͠Ωϡʔʹొ࿥͢Δ͜ͱ͕Ͱ͖ͳ͍ɻ new ReadableStream({ pull(controller) { controller.enqueue('pull'); } },{ size(chunk) { return chunk.length; }, highWaterMark: 100 }); 2VFVJOH4USBUFHZ

Slide 76

Slide 76 text

ʮ4USFBNT"1*ʯ TJODF0DU 4USFBNT˜8)"58( "QQMF (PPHMF .P[JMMB .JDSPTPGU -JDFOTFEVOEFS$$#:

Slide 77

Slide 77 text

4USFBNTʢͱͦͷपลʣͷࠓޙ

Slide 78

Slide 78 text

(JTDPNJOHUP+BQBOJO ɾߴ଎ɺେ༰ྔ ɾ௿஗Ԇ ɾଟ઀ଓ

Slide 79

Slide 79 text

ωοτϫʔΫʹؔ͢ΔύϑΥʔϚϯεվળࡦ ɾͰ͖Δ͚ͩϦΫΤετ਺΍ϑΝΠϧαΠζΛݮΒ͢ ɹɾεϓϥΠτը૾Λ࢖͏ ɹɾςΩετϑΝΠϧΛѹॖ͢Δ ɾQSFMPBE QSFGFUDI ɾΩϟογϡɺ$%/ͷར༻ ͜Ε·ͰϘτϧωοΫͱ͞Ε͖ͯͨ΋ͷ͕(ʹΑͬͯ վળ͞ΕΔɻ

Slide 80

Slide 80 text

ʮ(ͩ͠ɺϑΝΠϧαΠζͳΜͯؔ܎ͳ͍ΑͶ ʯ େ༰ྔͷϑΝΠϧ͕഑৴͞Εɺ ΫϥΠΞϯτͷॲཧ͕௥͍͔ͭͳ͘ͳΔ͔΋ʜʁ ʮΫϥ΢υήʔϛϯάαʔϏε࢝Ί͍ͨʂʯ ʮϥΠϒετϦʔϛϯάͰ഑৴͍ͨ͠ʂʯ

Slide 81

Slide 81 text

ʮ8FC$PEFDTʯ ϒϥ΢β͕උ͑ΔίʔσοΫ΍ίϯςφΛར༻͢ΔͨΊͷ"1*

Slide 82

Slide 82 text

ɾ4USFBNT-JWJOH4UBOEBSE೔ຊޠ༁ IUUQTUSJQMFVOEFSTDPSFHJUIVCJP4USFBNTKBIUNM ɾTUSFBNCFUXFFOOPEFKTBOEXIBUXH IUUQTTQFBLFSEFDLDPNKYDLTUSFBNCFUXFFOOPEFKTBOEXIBUXH ɾ4USFBN:PVS8BZUP*NNFEJBUF3FTQPOTFT IUUQTEFWFMPQFSTHPPHMFDPNXFCVQEBUFTTX SFBEBCMFTUSFBNT ɾࠓ೔ͷίʔυαϯϓϧͳͲ IUUQTHJUIVCDPNULTLUPTUSFBNFYBNQMFT ࢀߟࢿྉ

Slide 83

Slide 83 text

5IBOLZPV