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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
Heart of Swift Concurrency
koher
0
1.1k
Herb in Rails 8.2: Your ERB views, now HTML-aware @ Rails World 2026, Austin, Texas
marcoroth
0
150
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
470
Unity6 URPによる海底をテーマにしたVJシステムの解説 | Unity Shader 完全に理解した 勉強会
gam0022
0
300
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
300
IBM Bob Dojo #1 仕様駆動開発入門
oniak3ibm
PRO
0
330
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
520
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
190
iOSDC Japan 2026 - Swiftで作って学ぼう!データベース自作入門
kaseken
2
430
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
390
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.6k
GitHubハンズオン講座 — 実務レベルのチーム開発のフローを身につけよう
junhat6
0
120
Featured
See All Featured
[Rails World 2026] Durable orchestration on Rails: from continuation to workflow
palkan
1
410
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
320
A brief & incomplete history of UX Design for the World Wide Web: 1989–2019
jct
2
520
4 Signs Your Business is Dying
shpigford
187
23k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
First, design no harm
axbom
PRO
2
1.3k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
3
3.8k
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.9k
Claude Code のすすめ
schroneko
67
230k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
A Modern Web Designer's Workflow
chriscoyier
699
190k
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