Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Streams APIをちゃんと理解する
Search
kato takeshi
November 30, 2019
Programming
3.5k
4
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Streams APIをちゃんと理解する
JSConf JP 2019のセッションでお話しした内容です。
https://jsconf.jp/2019/talk/takeshi-kato
kato takeshi
November 30, 2019
Other Decks in Programming
See All in Programming
Jetpack Compose Mechanisms
skydoves
2
510
Heart of Swift Concurrency
koher
0
1.2k
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
1.1k
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
350
Agentic Software Factoryに、すごく賢いIF文を。 / super smart IF statement into the Agentic Software Factory.
rkaga
8
1.9k
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
190
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
390
見えないものを探る要求要件定義に必要な基本的思考 / invisible-requirement-thinking
minodriven
15
7.5k
CodeRabbitの効果検証と過ごしてみた3ヶ月
armondando
0
160
Simple Storage Service(S3) is not simple
iwatsukayura
0
210
AIに “答え“を書かせるのを やめてみた
___akari11
0
110
phperだってパンチカードでコーディングしたい
o0h
PRO
0
220
Featured
See All Featured
Balancing Empowerment & Direction
lara
6
1.3k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
68
58k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
550
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
720
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
450
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
570
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
570
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
920
Darren the Foodie - Storyboard
khoart
PRO
4
4k
The browser strikes back
jonoalderson
0
1.8k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
700
Agile that works and the tools we love
rasmusluckow
331
22k
Transcript
ʮ4USFBNΛͪΌΜͱཧղ͢Δʯ
4BVOB4QB)FBMUI"EWJTFS⽂ Takeshi Kato Frontend Developer in
ʮ4USFBNΛ੍͢Δͷɺ/PEFKTΛ੍͢ʯ IUUQKYDLIBUFOBCMPHDPNFOUSZ
ʮ4USFBNT"1*ʯ TJODF0DU 4USFBNT8)"58( "QQMF (PPHMF .P[JMMB .JDSPTPGU -JDFOTFEVOEFS$$#:
ʮ4USFBNT"1*ʯ TJODF0DU
4USFBNʁ ετϦʔϜʢӳTUSFBNʣͱɺ ࿈ଓͨ͠σʔλΛʮྲྀΕΔͷʯͱͯ͠ଊ͑ɺ ͦͷσʔλͷೖग़ྗ͋Δ͍ૹड৴Λѻ͏͜ͱͰ͋Γɺ ·ͨͦͷૢ࡞ͷͨΊͷநσʔλܕΛࢦ͢ɻ ग़యϑϦʔඦՊࣄయʰΟΩϖσΟΞʢ8JLJQFEJBʣʱ
αʔό ॲཧ ඳը αʔό ॲཧ ඳը XJUI4USFBN XJUIPVU4USFBN
αʔό αʔό XJUI4USFBN XJUIPVU4USFBN ॲཧ ඳը ॲཧ ඳը
3FBEBCMF 4USFBN 5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN ʮ4USFBNT"1*ʯ
5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN 3FBEBCMF 4USFBN
3FBEBCMF4USFBNʢಡΈࠐΈՄೳͳετϦʔϜʣ 2VF $IVOL 6OEFSMZJOH4PVSDF %BUB ɾ6OEFSMZJOH4PVSDF ɹσʔλͷݯͱͳΔΦϒδΣΫτɻը૾ಈըͳͲͷϝσΟΞ͚ͩͰͳ͘ ɹςΩετɺͳͲѻ͑Δɻ ɾ\3FBEBCMF4USFBN%FGBVMU$POUSPMMFS^ ɹετϦʔϜͷঢ়ଶ෦Ωϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻᶃͷૢ࡞Λ୲͢Δɻ
ɾ\3FBEBCMF4USFBN%FGBVMU3FBEFS^ ɹετϦʔϜ͔ΒνϟϯΫΛಡΈऔΔΫϥεɻᶄͷૢ࡞Λ୲͢Δɻ ᶃ ᶄ
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); });
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); });
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); });
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); });
$BTFʮ4USFBNJOH3FTQPOTFʯ
'FUDI"1*࣮ߦޙʹड͚औΕΔ3FTQPOTFͷ#PEZ ʮ3FBEBCMF4USFBNʯ ``` fetch(url).then(response => response.body).then(readableStream => { // do
something }); ```
4FSWJDF8PSLFSͰϦΫΤετΛΠϯλʔηϓτͯ͠ɺ 4USFBNΛ3FTQPOTFͱͯ͠ฦ͢
4BNQMF
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
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
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’} }));
``` caches.match(request).then(res => res.body).then(readableStream => { // do something });
``` $BDIF"1*࣮ߦޙʹड͚औΕΔ3FTQPOTFͷ#PEZ ʮ3FBEBCMF4USFBNʯ
ϔομʔʢDBDIFʣ ίϯςϯπʢGFUDIʣ ϑολʔʢDBDIFʣ ͷΑ͏ͳ͜ͱͰ͖Δ
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
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
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
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
3FBEBCMF4USFBNΛ͏ͱ σʔλΛׂͯ͠গͣͭ͠ ಡΈࠐΉ͜ͱ͕Ͱ͖Δ
5SBOTGPSN 4USFBN 3FBEBCMF 4USFBN 8SJUBCMF 4USFBN
8SJUBCMF4USFBNʢॻ͖ࠐΈՄೳͳετϦʔϜʣ 2VF 6OEFSMZJOH4JOL /FX%BUB ɾ\6OEFSMZJOH4JOL^ ɹΩϡʔ͔ΒνϟϯΫΛड͚औͬͯॻ͖ࠐΈΛߦ͏ΦϒδΣΫτɻ ɾ\8SJUBCMF4USFBN%FGBVMU8SJUFS^ ɹ8SJUBCMF4USFBNʹνϟϯΫΛॻ͖ࠐΉ͜ͱ͕Ͱ͖ΔΫϥεɻ ɹᶃͷૢ࡞Λ୲͢Δɻ ɾ\8SJUBCMF4USFBN%FGBVMU$POUSPMMFS^
ɹετϦʔϜͷঢ়ଶ෦Ωϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻᶄͷૢ࡞Λ୲͢Δɻ ᶄ ᶃ
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.'))
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.'))
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.'))
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.'))
3FBEBCMF 4USFBN 8SJUBCMF 4USFBN QJQF5P
$BTFʮ/BUJWF'JMF4ZTUFNʯ ʮϑΝΠϧΛ'FUDIͯ͠ɺυϥΠϒʹॻ͖ࠐΈʯ
4BNQMF
fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter
= await handle.createWriter(); // handleNativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ 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); })
fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter
= await handle.createWriter(); // handleNativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ 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); })
fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter
= await handle.createWriter(); // handleNativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ 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); })
fetch('https://streams.spec.whatwg.org/').then(async (res) => { const readableStream = res.body; const fileWriter
= await handle.createWriter(); // handleNativeFileSystemAPI͔ΒಘͨΦϒδΣΫτ 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); })
/BUJWF'JMF4ZTUFN Y 4USFBNT"1* IUUQTHJUIVCDPNXJDHOBUJWFpMFTZTUFNJTTVFT 4USFBNΛ༻ͨ͠ॻ͖ࠐΈͷ࣮͕ʢଟʣਐΜͰ͍Δ
8SJUBCMF4USFBNΛ͏ͱ ׂ͞ΕͨσʔλΛ Ұͭͣͭɺॱ൪ʹ ॻ͖ࠐΉ͜ͱ͕Ͱ͖Δ
3FBEBCMF 4USFBN 8SJUBCMF 4USFBN 5SBOTGPSN 4USFBN
5SBOTGPSN4USFBNɹʢมετϦʔϜʣ 8SJUBCMF4USFBN 5SBOTGPSNFS 3FBEBCMF4USFBN ɾ\XSJUBCMF SFBEBCMF^ ɹ8SJUBCMF4USFBNͱ3FBEBCMF4USFBNΛแ͍ͯ͠Δɻ ɾ\5SBOTGPSNFS^ ɹ8SJUBCMF4USFBN͔Β$IVOLΛड͚औͬͯɺมॲཧΛߦ͏ΦϒδΣΫτɻ ɾ\5SBOTGPSN4USFBN%FGBVMU$POUSPMMFS^
ɹ8SJUBCMFɺ3FBEBCMF4USFBNͷঢ়ଶΩϡʔͷ੍ޚͳͲΛߦ͏Ϋϥεɻ
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 });
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 });
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 });
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 });
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 });
3FBEBCMF 4USFBN 5SBOTGPSN 4USFBN 8SJUBCMF 4USFBN QJQF5ISPVHI 3&563/3FBEBCMF4USFBN QJQF5P
3&563/1SPNJTF
5FYU&ODPEFS4USFBNɾ5FYU%FDPEFS4USFBN GSPN&ODPEJOH"1*
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 });
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
$BTFʮ༁ʯ
4BNQMF
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));
} }); } 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)); } }); }
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); }); } });
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')); });
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')); });
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
ಉ͡3FBEBCMFετϦʔϜΛ͍͍ͨ߹ೋຢԽʢUFFʣ͢Δඞཁ͕͋ Γ·͢ɻ ྫʣJOQVU<UZQFlpMFz>ͰΞοϓϩʔυͨ͠ϑΝΠϧΛTUSFBNͰѻ͏ྫ MPDLFEͱUFF input.addEventListener('change', function () { const stream
= input.files[0].stream(); // ͓͓ͱΛڞ༗ͨ͠2ͭͷStreamͷྻ͕ಘΒΕΔ const [org, translated] = stream.tee(); … });
5SBOTGPSN4USFBNΛ͏ͱ νϟϯΫΛྲྀΕΔΑ͏ʹม͠ɺ ͞ΒʹಡΈࠐΈ͢͜ͱ͕Ͱ͖Δ
3FBEBCMF 4USFBN 8SJUBCMF 4USFBN 5SBOTGPSN 4USFBN
ͦͷଞͷ֓೦ͱ"1* ɾഎѹʢ#BDL1SFTTVSFʣ ɾ1VTI4PVSDFͱ1VMM4PVSDF ɾ2VFVJOH4USBUFHZ
3FBEBCMF 4USFBN 8SJUBCMF 4USFBN #BDL1SFTTVSFͱ ޙΖ͕٧·ͬͨʢΩϡʔʹۭ͖͕ͳ͘ͳͬͨʣ࣌ʹɺ
8SJUBCMF 4USFBN 3FBEBCMF 4USFBN #BDL1SFTTVSFͱ ޙΖ͕٧·ͬͨʢΩϡʔʹۭ͖͕ͳ͘ͳͬͨʣ࣌ʹɺ ύΠϓΛ௨ͯ͠લͷετϦʔϜʹ௨͢Δ
ɾ1VTI4PVSDF ɹ4PVSDFଆ͔ΒࣗൃతʹFORVFVF͢ΔλΠϓ FH4PDLFU ɾ1VMM4PVSDF ɹϦΫΤετʹԠͯ͡FORVFVF͢ΔλΠϓ FHϑΝΠϧϋϯυϧ ɹ 6OEFSMZJOH4PVSDFͷͭͷλΠϓ
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ͱ͍͏Θ͚Ͱ͋Γ·ͤΜɻ
1VTI4PVSDF new ReadableStream({ start(controller) { socket.addEventListener('message', (e) => { controller.enqueue(e.data);
}); } }); 1VMM4PVSDF new ReadableStream({ pull(controller) { controller.enqueue(Math.random()); } }); QVMMϝιου Ωϡʔʹۭ͖͕ͳ͘ͳΔ·Ͱ ࣮ߦ͞ΕΔ
1VTI4PVSDF new ReadableStream({ start(controller) { socket.addEventListener('message', (e) => { controller.enqueue(e.data);
}); } }); 1VMM4PVSDF new ReadableStream({ pull(controller) { controller.enqueue(Math.random()); } }); QVMMϝιου Ωϡʔʹۭ͖ʢʁʣ͕ͳ͘ͳΔ·Ͱ ࣮ߦ͞ΕΔ
֤ετϦʔϜ͕࣋ͭΩϡʔʹอ࣋Ͱ͖ΔαΠζͱ࠷େʢͭ·Γۭ͖ʣΛ ܾΊΔΦϒδΣΫτɻΦϒδΣΫτҎԼͷϓϩύςΟΛ࣋ͭɻ ɾIJHI8BUFS.BSLOVNCFS ɹετϦʔϜͷݶքਫҐʢΩϟύγςΟʣΛࢦఆ͢Δɻɹ )8.ʢΩϡʔʹొ͞Ε͍ͯΔνϟϯΫͷ߹ܭαΠζʣ ɾTJ[F DIVOL OVNCFS ɹԿΛͬͯΩϡʔͷαΠζΛදݱ͢Δ͔Λܾఆ͢Δؔɻ 2VFVJOH4USBUFHZ
ྫʣDIVOLΛจࣈྻͱͯ͠ड͚औΔ͜ͱΛఆͨ͠߹ɺ ɹ͜ͷ4USFBN߹ܭจࣈ·Ͱ͔͠Ωϡʔʹొ͢Δ͜ͱ͕Ͱ͖ͳ͍ɻ new ReadableStream({ pull(controller) { controller.enqueue('pull'); } },{ size(chunk)
{ return chunk.length; }, highWaterMark: 100 }); 2VFVJOH4USBUFHZ
ʮ4USFBNT"1*ʯ TJODF0DU 4USFBNT8)"58( "QQMF (PPHMF .P[JMMB .JDSPTPGU -JDFOTFEVOEFS$$#:
4USFBNTʢͱͦͷपลʣͷࠓޙ
(JTDPNJOHUP+BQBOJO ɾߴɺେ༰ྔ ɾԆ ɾଟଓ
ωοτϫʔΫʹؔ͢ΔύϑΥʔϚϯεվળࡦ ɾͰ͖Δ͚ͩϦΫΤετϑΝΠϧαΠζΛݮΒ͢ ɹɾεϓϥΠτը૾Λ͏ ɹɾςΩετϑΝΠϧΛѹॖ͢Δ ɾQSFMPBE QSFGFUDI ɾΩϟογϡɺ$%/ͷར༻ ͜Ε·ͰϘτϧωοΫͱ͞Ε͖ͯͨͷ͕(ʹΑͬͯ վળ͞ΕΔɻ
ʮ(ͩ͠ɺϑΝΠϧαΠζͳΜͯؔͳ͍ΑͶ ʯ େ༰ྔͷϑΝΠϧ͕৴͞Εɺ ΫϥΠΞϯτͷॲཧ͕͍͔ͭͳ͘ͳΔ͔ʜʁ ʮΫϥυήʔϛϯάαʔϏε࢝Ί͍ͨʂʯ ʮϥΠϒετϦʔϛϯάͰ৴͍ͨ͠ʂʯ
ʮ8FC$PEFDTʯ ϒϥβ͕උ͑ΔίʔσοΫίϯςφΛར༻͢ΔͨΊͷ"1*
ɾ4USFBNT-JWJOH4UBOEBSEຊޠ༁ IUUQTUSJQMFVOEFSTDPSFHJUIVCJP4USFBNTKBIUNM ɾTUSFBNCFUXFFOOPEFKTBOEXIBUXH IUUQTTQFBLFSEFDLDPNKYDLTUSFBNCFUXFFOOPEFKTBOEXIBUXH ɾ4USFBN:PVS8BZUP*NNFEJBUF3FTQPOTFT
IUUQTEFWFMPQFSTHPPHMFDPNXFCVQEBUFTTX SFBEBCMFTUSFBNT ɾࠓͷίʔυαϯϓϧͳͲ IUUQTHJUIVCDPNULTLUPTUSFBNFYBNQMFT ࢀߟࢿྉ
5IBOLZPV