Using readable streams
JavaScript ê°ë°ìë¡ì, íë¡ê·¸ëë°ì ì¼ë¡ ë¤í¸ìí¬ë¡ë¶í° ë°ì ë°ì´í° ì¤í¸ë¦¼ì Chunkë¨ìë¡ ì½ê³ ë¤ë£¨ë ê²ì ë§¤ì° ì ì©í©ëë¤! ê·¸ë¬ë ì´ë»ê² ì¤í¸ë¦¼ APIì Readable streamì ì ì¬ì©í ì ììê¹ì. ì´ë² ë´ì©ì ê·¸ê²ì ì¤ëª íê³ ììµëë¤.
ì°¸ê³ : This article assumes that you understand the use cases of readable streams, and are aware of the high-level concepts. If not, we suggest that you first read the Streams concepts and usage overview and dedicated Streams API concepts article, then come back.
ì°¸ê³ : If you are looking for information on writable streams try Using writable streams instead.
Browser support
Firefox 65+ ì í¬ë¡¬ 42+ ìì Fetch Body ê°ì²´ë¥¼ ì¤í¸ë¦¼ì¼ë¡ì ì¬ì© í ì ìê³ , custom readable ì¤í¸ë¦¼ì ë§ë¤ì ììµëë¤. íì¬ Pipe chainsì ê²½ì° ì¤ì§ í¬ë¡¬ììë§ ì§ìíê³ ìê³ ê·¸ 기ë¥ì ë³ê²½ë ì ììµëë¤.
Finding some examples
ì´ë² ë´ì©ê³¼ ê´ë ¨í ë§ì ìì 를 dom-examples/streams ìì ì´í´ë³¼ì ììµëë¤. ì´ê³³ìì 모ë ìì¤ë¥¼ íì¸í ì ìì ë¿ë§ ìëë¼ ìì ì¬ì´í¸ ë§í¬ë íì¸í ì ììµëë¤.
Consuming a fetch as a stream
Fetch API ë ë¤í¸ìí¬ë¥¼ íµí´ 리ìì¤ë¥¼ ê°ì ¸ì¤ë XHRì íëì ì¸ ëìì± ì ëë¤. Fetch APIì ìë§ì ì´ì ê°ì´ë° ê°ì¥ íë¥íì ì ìµê·¼ ë¸ë¼ì°ì ë¤ì´ Fetch Response를 Readable ì¤í¸ë¦¼ì¼ë¡ ì´ì©í ì ìê² íë 기ë¥ì ì¶ê°íê² ì ëë¤.
Body 믹ì¤ì¸ì body ìì±ì í¬í¨íê³ ììµëë¤. ê·¸ë¦¬ê³ ì´ body ìì±ì bodyì ë´ì©ì Readable ì¤í¸ë¦¼ì¼ë¡ ë
¸ì¶ìí¤ë ê°ë¨í getter ì
ëë¤. ì´ Body 믹ì¤ì¸ì Requestì Response ì¸í°íì´ì¤ë¡ë¶í° 구í ëë©°, ë°ë¼ì ë ê²½ì° ëª¨ë ì¬ì© í ì ììµëë¤. ë¤ë§ Response bodyì ì¤í¸ë¦¼ì ì¬ì©íë ê²ì´ ì¡°ê¸ë ëª
íí©ëë¤.
ì°ë¦¬ì Simple stream pumpìììì ë³´ì¬ì£¼ë¯(see it live also), Readable ì¤í¸ë¦¼ì ë ¸ì¶ìí¤ê¸° ìí´ìë ë¨ì§ Responseì body ìì±ì ì ê·¼íê¸°ë§ íë©´ ë©ëë¤.
// ì¤ë¦¬ì§ë ì´ë¯¸ì§ë¥¼ Fetch í¨
fetch("./tortoise.png")
// body 를 ReadableStreamì¼ë¡ ê°ê³µí¨
.then((response) => response.body);
ì´ê²ì ì°ë¦¬ìê² ReadableStream ê°ì²´ë¥¼ ì ê³µí´ ì¤ëë¤.
Attaching a reader
ì´ì ì°ë¦¬ë ì¤í¸ë¦¼íë body를 ê°ì§ê³ ìì¼ë©°, ì´ ì¤í¸ë¦¼ì ì½ê¸° ìí´ìë 리ë기를 ë¶ì¬ì¼ í©ëë¤. ì´ ìì
ì ReadableStream.getReader() ë©ìë를 ì¬ì©íì¬ ì²ë¦¬í©ëë¤.
// ì¤ë¦¬ì§ë ì´ë¯¸ì§ë¥¼ Fetch í¨
fetch('./tortoise.png')
// body 를 ReadableStreamì¼ë¡ ê°ê³µí¨
.then(response => response.body)
.then(body => {
const reader = body.getReader();
ì´ ë©ìë를 ì¤ííë©´ 리ëê¸°ê° ìì±ëê³ ì´ ë¦¬ë기를 ì¤í¸ë¦¼ì ê³ ì (locks) ìíµëë¤. ReadableStreamDefaultReader.releaseLock() ë©ìë를 ì¬ì©íëë± ì´ ê³ ì (locks)ì í기ì ê¹ì§ë(released), ê·¸ ì´ë¤ ë¤ë¥¸ 리ë기ë¤ë ì´ ì¤í¸ë¦¼ì ì½ìì ììµëë¤.
ëí response.body ë ë기ì´ë¯ë¡ êµ³ì´ íë¡ë¯¸ì¤ë¥¼ ì¬ì©í íìê° ìì¼ë©°, ìì ìì를 íë²ì ì¤í
ì¼ë¡ ì¤ì¼ì ìë¤ë ì ì ì£¼ëª©í´ ì£¼ììì
// ì¤ë¦¬ì§ë ì´ë¯¸ì§ë¥¼ Fetch í¨
fetch('./tortoise.png')
// body 를 ReadableStreamì¼ë¡ ê°ê³µí¨
.then(response => {
const reader = response.body.getReader();
Reading the stream
ì´ì ì°ë¦¬ë ì°ë¦¬ì 리ë기를 ì¶ê°íììµëë¤. ì°ë¦¬ë 리ë기ì ReadableStreamDefaultReader.read() ë©ìë를 ì¬ì©íì¬ ì¤í¸ë¦¼ì¼ë¡ ë¶í° data chunkë¤ì ì½ìì ìê² ëììµëë¤.
ì ííê²ë ì´ ë©ìëë ê° ì¤í¸ë¦¼ì¼ë¡ë¶í° íëì data chunk를 ì½ìµëë¤. ê·¸ë¦¬ê³ ì´ë¬í data chunkë ì°ë¦¬ê° ìíëëë¡ ì¬ì©í ì ììµëë¤.
ì를 ë¤ì´ ì°ë¦¬ì Simple stream pump exampleììë ReadableStreamDefaultReader.read() ì¬ì©íì¬ Data Chunk를 ìë¡ì´ 커ì¤í
ReadableStreamì ì§ì´ ë£ê³ ììµëë¤. ê·¸ë¦¬ê³ ë§ì½ ì½ìì ìë ë¤ì Data Chunkê° ìë¤ë©´, ReadableStreamDefaultReader.read() 를 ë¤ì ì¬ì©íì¬ ë¤ì Data Chunk를 커ì¤í
ReadableStreamì ì§ì´ ë£ìµëë¤. ëì´ì ì½ìì ìë Data Chunkê° ìë¤ë©´, ê·¸ 커ì¤í
ReadableStream(ì°ë¦¬ë ì´ ìë¡ì´ Readable ì¤í¸ë¦¼ì ëí´ ë¤ì ì¹ì
ìì ë¤ ìì¸í ì´í´ ë³¼ê² ì
ëë¤.)ì íµí´ ìë¡ì´ Response ê°ì²´ë¥¼ ìì±í©ëë¤. ê·¸ ë¤ì ì´ Response ê°ì²´ë¥¼ Blob ííë¡ ë³ííê³ ì´ Blob ì¼ë¡ ë¶í° URL.createObjectURL() ë©ìë를 ì¬ì©íì¬ URL ê°ì²´ë¥¼ ìì±í©ëë¤. ë§ì§ë§ì¼ë¡ ì´ URLê°ì²´ë¥¼ {htmlelement("img")}} ì ì ì©íì¬ ì´ë¯¸ì§ë¥¼ ë³´ì¬ì¤ì¼ë¡ì fetchë ì¤ë¦¬ì§ë ì´ë¯¸ì§ë¥¼ í¨ê³¼ì ì¼ë¡ ë³µì¬íë ê²ì
ëë¤.
return new ReadableStream({
start(controller) {
return pump();
function pump() {
// ì¤í¸ë¦¼ì ë¤ì Chunkì ëí ì¡ì¸ì¤ë¥¼ ì ê³µíë psomise를 리í´íë¤.
return reader.read().then(({ done, value }) => {
// ëì´ì ì½ì ë°ì´í° ì¡°ê°ì´ ììë ì¤í¸ë¦¼ì ë«ëë¤
if (done) {
controller.close();
return;
}
// ë°ì´í° ì¡°ê°ì ìë¡ì´ ì¤í¸ë¦¼(ìë¡ ë§ëë 커ì¤í
ì¤í¸ë¦¼)ì ë£ëë¤.
controller.enqueue(value);
return pump();
});
}
}
})
})
.then(stream => new Response(stream))
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(url => console.log(image.src = url))
.catch(err => console.error(err));
ì´ë»ê² read() ê° ì¬ì©ëìëì§ ìì¸í ë¤ì¬ë¤ ë´
ìë¤. ì ìì ì pump() í¨ìë ì ì¼ë¨¼ì read() 를 ì¤ííììµëë¤. ê·¸ë¦¬ê³ ì´ read() ë ì¤í¸ë¦¼ì¼ë¡ë¶í° ì½ì´ ë¤ì¸ ë´ì©ì 결과를 { done, value } ì íìì¼ë¡ ê°ì§ê³ ìë pomise를 ë°íí©ëë¤.
return reader.read().then(({ done, value }) => {
ì¤í¸ë¦¼ì¼ë¡ë¶í° ì½ì´ ë¤ì¸ ë´ì©ì ìë 3ê°ì§ íì ì´ ììµëë¤.
- chunk를 ìì§ ì½ìì ìë ê²½ì°ì íë¡ë¯¸ì¤ë
{ value: theChunk, done: false }ê°ì²´ì í¨ê» fulfill ë©ëë¤. - ì¤í¸ë¦¼ì´ ë«í ê²½ì°ì íë¡ë¯¸ì¤ë
value: undefined, done: true }ê°ì²´ì í¨ê» fulfill ë©ëë¤. - ì¤í¸ë¦¼ìì ì ë¬ê° ë°ìí ê²½ì° promiseë ê´ë ¨ ì ë¬ì í¨ê» reject ë©ëë¤.
ë¤ìì¼ë¡ ì°ë¦¬ë done ì´ true ì¸ì§ ìëì§ íì¸í´ ë´ì¼ í©ëë¤.
ë§ì½ done ì´ true ë¼ë©´ ëì´ì ì½ì´ë¤ì¼ chunkê° ìë¤ë ë»ì
ëë¤. ë°ë¼ì ì°ë¦¬ë í¨ì ë°ì¼ë¡ ë¹ ì ¸ ëê°ì¼ íê³ ReadableStreamDefaultController.close() 를 íµíì¬ ì»¤ì¤í
ì¤í¸ë¦¼ì ë«ìì¼ í©ëë¤.
if (done) {
controller.close();
return;
}
ì°¸ê³ :
ì¬ê¸°ì ì¬ì©í close() ë ìë¡ë§ë 커ì¤í
ì¤í¸ë¦¼ì ì¼ë¶ì´ë©° ì¤ë¦¬ì§ë ì¤í¸ë¦¼ì ê²ì´ ìëëë¤. 커ì¤í
ì¤í¸ë¦¼ì ëí´ìë ë¤ìì¹ì
ìì ë ìì¸í ì´í´ ë³¼ ìì ì
ëë¤.
ë§ì½ done ì´ true ê° ìëë¼ë©´, ì°ì ì½ì´ ë린 Chunk를 ì²ë¦¬íê³ (value ìì±), pump() í¨ì를 ì¬ê·ì ì¼ë¡ ë¤ì í¸ì¶ í¨ì¼ë¡ì ë¤ì chunk를 ì½ì´ ë립ëë¤.
// ë¤ì data chunk를 ìë¡ì´ readable ì¤í¸ë¦¼ì ì§ì´ ë£ì
controller.enqueue(value);
return pump();
ë¤ìì ì¤í¸ë¦¼ 리ë기를 ì¬ì©í ëì 기본ì ì¸ í¨í´ ì ëë¤.
- ì¤í¸ë¦¼ì ì½ìì¼ë¡ì ì¤íëë í¨ì를 ìì±í©ëë¤.
- ë§ì½ ì½ìì ìë ì¤í¸ë¦¼ì´ ëì´ì ìë¤ë©´, í¨ì를 ë¦¬í´ ìíµëë¤.
- ë§ì½ ì½ìì ìë ì¤í¸ë¦¼ì´ ìì§ ë¨ì ìë¤ë©´, ì°ì ì½ì´ ë린 chunk를 ì²ë¦¬íê³ , ë¤ì chunk를 ì½ì´ ë리기 ìí´ í¨ì를 ë¤ì ì¤íí©ëë¤.
- ëì´ì ì½ìì ìë ì¤í¸ë¦¼ì´ ììëê¹ì§ í¨ì를 ì¬ê·ì ì¼ë¡ ì¤ííê³ , ìµì¢ ì ì¼ë¡ ì½ìì ìë ì¤í¸ë¦¼ì´ ììê²½ì° 2ë² Stepì ë°ë¦ ëë¤.
Creating your own custom readable stream
ëë²ì§¸ íí¸ìì ì¬ì©íë Simple stream pump example ìì ìì ì°ë¦¬ë fetch bodyë¡ ë¶í° ì½ì´ë린 ì´ë¯¸ì§ì ëí data를 ì°ë¦¬ê° ìì²´ì ì¼ë¡ ë§ë 커ì¤í
readable ì¤í¸ë¦¼ì ë¤ì ì®ê²¨ ì¬ììµëë¤. ê·¸ë¼ ì´ë»ê² ì¤í¸ë¦¼ììì²´ì ì¼ë¡ ë§ë¤ì ììê¹ì? ì°ë¦¬ë ReadableStream()ìì±ì í¨ì를 íµí´ 커ì¤í
readable ì¤í¸ë¦¼ì ë§ë¤ ì ììµëë¤.
The ReadableStream() constructor
Fetchì ê°ì´ ë¸ë¼ì°ì ìì ì¤í¸ë¦¼ì ì ê³µí ë ê·¸ê²ì ì½ì´ ë¤ì´ë ì¼ì ì¬ì´ ì¼ì
ëë¤. ê·¸ë¬ë ëëë¡ ìë¡ì´ 커ì¤í
ì¤í¸ë¦¼ì ë§ë¤ê³ ì´ê²ì data chunkë¤ë¡ ì±ìë£ì´ì¼ íë ê²½ì°ê° ììµëë¤. ReadableStream()ì ìëì 구문과 ê°ì´ ì¬ì©í¨ì¼ë¡ì ì´ê²ì ê°ë¥íê² í ì ììµëë¤. êµ¬ë¬¸ì´ ì²ììë ë¤ì ë³µì¡í´ ë³´ì¼ì ììµëë¤ë§, ì¤ì ë¡ë ê·¸ë ê² ë³µì¡íì§ ììµëë¤.
기본ì ì¸ íµì¬ 구문ì ë¤ìê³¼ ê°ìµëë¤.
const stream = new ReadableStream({
start(controller) {
},
pull(controller) {
},
cancel() {
},
type,
autoAllocateChunkSize
}, {
highWaterMark,
size()
});
ìì±ì í¨ìë ëê°ì ê°ì²´ë¥¼ ì¸ìë¡ ë°ìµëë¤. 첫ë²ì§¸ ì¸ìë íì ê°ì´ë©°, ì´ê²ì ì°ë¦¬ê° ì½ì´ ë¤ì¼ 기본 ìì¤ì 모ë¸ì JavasScrip ì ì¼ë¡ ìì± í©ëë¤. ëë²ì§¸ ì¸ìë ìµì ê°ì´ë©°, ì´ê²ì 커ì¤í ì¤í¸ë¦¼ì ì¬ì©í 커ì¤í queuing ì ëµì ì립íê² í©ëë¤. ëë²ì§¸ ì¸ìì ê²½ì° ë§¤ì° ëë¬¼ê² ì¤ì íë ê°ì´ë¯ë¡ ì§ê¸ì 첫ë²ì§¸ ì¸ìì ì§ì¤íëë¡ íê² ìµëë¤.
첫ë²ì§¸ ì¸ìì¸ ê°ì²´ë 5ê°ì ë§´ë²ë¥¼ ê°ì§ì ìì¼ë©°, ì ì¼ ì²«ë²ì§¸ ë§´ë²ë§ íì ì ëë¤.
start(controller)âReadableStreamì´ ìì±ëì ë§ì ë± íë²ë§ í¸ì¶ ëë ë©ìë ì ëë¤. ì´ ë©ìëìë ì¤í¸ë¦¼ì 기ë¥ì ì¤ì í ì ìë ì½ëê° í¬í¨ëì´ì¼ í©ëë¤. ì를 ë¤ë©´ ë°ì´í° ìì±ì ììíë¤ê±°ë ìëë©´ ìì¤ì ì ê·¼íì¬ ë°ì´í°ë¥¼ ê°ì ¸ì¤ë ì½ëë±ì´ ë¤ì´ê°ê² ë ê²ì ëë¤.pull(controller)â ì´ ë©ìëë ì¤í¸ë¦¼ ë´ë¶ì queueê° ê°ë ì°°ëê¹ì§ ë°ë³µì ì¼ë¡ í¸ì¶ ë©ëë¤. ë ë§ì ì²í¬ê° íì ë¤ì´ê° ë ì¤í¸ë¦¼ì ì ì´íë ë° ì¬ì©í ì ììµëë¤.cancel()â ì´ ë©ìëë ì¤í¸ë¦¼ì´ ìºì¬ë ë í¸ì¶ ë©ëë¤ (ì를 ë¤ì´ {domxref("ReadableStream.cancel()")}} ì´ í¸ì¶ ëììë). ë©ìëì ë´ì©ì ì¤í¸ë¦¼ ìì¤ì ëí ì¡ì¸ì¤ë¥¼ í´ì íë ë° íìí 모ë ê²ì ìíí´ì¼í©ëë¤.typeandautoAllocateChunkSizeâ ì¤í¸ë¦¼ì´ ë°ì´í¸ ì¤í¸ë¦¼ìì ëí ë´ê¸° ìí´ ì¬ì©ë©ëë¤. ë°ì´í¸ ì¤í¸ë¦¼ì 목ì ê³¼ ì¬ì© ì¬ë¡ê° ì¼ë° (기본) ì¤í¸ë¦¼ê³¼ ì½ê° ë¤ë¥´ë¯ë¡ í¥í ììµììì ë³ëë¡ ë¤ë£° ê²ì ëë¤. ëí ìì§ ì´ë ê³³ììë 구íëì§ ìììµëë¤.
simple example code 를 ë¤ìíë² ì´í´ë³´ë©´, ReadableStream() ìì±ìê° start() ë©ìë ë¨ íëë§ ê°ì§ê³ ìë¤ë ê²ì ììì±ì ìì ê² ì
ëë¤. ì´ start() ë©ìë fetchë ì¤í¸ë¦¼ì¼ë¡ ë¶í° ë°ì´í°ë¥¼ ì½ì´ ë¤ì´ê³ ììµëë¤.
return new ReadableStream({
start(controller) {
return pump();
function pump() {
return reader.read().then(({ done, value }) => {
// ëì´ì ì½ìì ìë dataê° ìë¤ë©´ ì¤í¸ë¦¼ì ë«ëë¤
if (done) {
controller.close();
return;
}
// ë°ì´í° ì¡°ê°ì ìë¡ì´ ì¤í¸ë¦¼(ìë¡ ë§ëë 커ì¤í
ì¤í¸ë¦¼)ì ë£ëë¤.
controller.enqueue(value);
return pump();
});
}
}
})
})
ReadableStream controllers
ReadableStream() ìì±ìì ì¸ìë¡ ì ë¬ë ê°ì²´ìì start() ì pull() ë©ìëì controllerë¼ë ì¸ìê° ì ë¬ëë ê²ì ë³¼ì ììµëë¤. ì´ê²ì ReadableStreamDefaultController í´ëì¤ì ì¸ì¤í´ì¤ì´ë©° ì°ë¦¬ì ì¤í¸ë¦¼ì ì ì´íëë° ì¬ì© ë©ëë¤.
ì°ë¦¬ì ìì ìì, ì°ë¦¬ë fetchë bodyë¡ë¶í° chunkì ê°ì ì½ì ë¤ ê·¸ ê°ì 커ì¤í
ì¤í¸ë¦¼ì ì§ì´ ë£ê¸° ìí´ Controllerì enqueue() ë©ìë를 ìì©íê³ ììµëë¤.
ëí, fetchë body를 ì½ì´ ë¤ì´ë ê²ì´ ëëë©´ 컨í¸ë¡¤ë¬ì close()를 ì¬ì©íì¬ ì»¤ì¤í
ì¤í¸ë¦¼ì ë«ìµëë¤. ì´ë ì´ë¯¸ ì½ì
ë chunkë¤ì ì¬ì í ì½ìì ìì§ë§ ìë¡ì´ chunkë ì§ì´ ë£ìì ììµëë¤. ê·¸ë¦¬ê³ ì½ë ê²ì´ 모ë ê¸ëë©´ ì¤í¸ë¦¼ì ë«íëë¤.
Reading from custom streams
ì°ë¦¬ì Simple stream pump example ìì, ì°ë¦¬ë {domxref("Response.Response", "Response")}} ìì±ì í¨ìì ì°ë¦¬ê° ë§ë 커ì¤í
readable ì¤í¸ë¦¼ì ì¸ìë¡ ì ë¬íìì¼ë©° ê·¸ë ê² ìì±ë response ì¸ì¤í´ì¤ë¥¼ blob() ì¼ë¡ ì¬ì© íììµëë¤.
.then(stream => new Response(stream))
.then(response => response.blob())
.then(blob => URL.createObjectURL(blob))
.then(url => console.log(image.src = url))
.catch(err => console.error(err));
ê·¸ë¬ë 커ì¤í
ì¤í¸ë¦¼ì ì¬ì í ReadableStream ì¸ì¤í´ì¤ì
ëë¤. ì¦, ì°ë¦¬ë ì¬ì í 리ë기를 커ì¤í
ì¤í¸ë¦¼ì ë¶ì¼ì ìë¤ë ë»ì
ëë¤. ì를 ë¤ì´ Simple random stream demo (see it live also) 를 ì´í´ ë³´ììì. ì´ ìì ììë 커ì¤í
ì¤í¸ë¦¼ì ìì±íí, ëë¤ ë¬¸ìì´ì ìì±ë 커ì¤í
ì¤í¸ë¦¼ì ì§ì´ ë£ìµëë¤. ê·¸ í 문ìì´ ìì± ì¤ì§ ë²í¼ì ëë ìë 커ì¤í
ì¤í¸ë¦¼ì ì§ì´ ë£ìë ëë¤ ë¬¸ìì´ì 커ì¤í
ì¤í¸ë¦¼ì¼ë¡ ë¶í° ë¤ì ì½ì´ ìµëë¤.
Note: FetchEvent.respondWith() ë©ìë를 ì¬ì©íì¬ ì¤í¸ë¦¼ì ë¤ë£¨ê¸° ìí´ìë ì¤í¸ë¦¼ì ì½ì
ë ë´ì©ì´ ë§ëì Uint8Array ì´ì´ì¼ í©ëë¤. (TextEncoder ë±ì ì¬ì©)
Simple random stream demo (see it live also) ìì 커ì¤í
ì¤í¸ë¦¼ ìì±ì í¨ìë start() ë©ìë를 ê°ì§ê³ ìì¼ë©°, ì´ ë©ìëë WindowTimers.setInterval() ì ì¬ì©íì¬ ë§¤ì´ë§ë¤ ìë¡ì´ ëë¤ ë¬¸ìì´ì ìì±íê³ ì´ ë¬¸ìì´ì ReadableStreamDefaultController.enqueue() 를 ì¬ì©íì¬ ì¤í¸ë¦¼ìì ë£ìµëë¤. ë§ì½ 문ìì´ ìì± ì¤ì§ ë²í¼ì ë른ë¤ë©´ ì´ interval ì´ ì·¨ìë¨ê³¼ ëìì readStream() í¨ì를 í¸ì¶íì¬ ì¤í¸ë¦¼ì¼ë¡ ë¶í° ì¤í¸ë¦¼ì ë£ì 문ìì´ ì ë¶ë¥¼ ì½ì´ ë립ëë¤. ì´ë ì¤í¸ë¦¼ì chunk data(ì¬ê¸°ìë ëë¤ ë¬¸ìì´)를 ë£ë ê²ë ì¤ë¨ í기ë문ì ì¤í¸ë¦¼ì ë«ìµëë¤.
const stream = new ReadableStream({
start(controller) {
interval = setInterval(() => {
let string = randomChars();
// Add the string to the stream
controller.enqueue(string);
// show it on the screen
let listItem = document.createElement("li");
listItem.textContent = string;
list1.appendChild(listItem);
}, 1000);
button.addEventListener("click", function () {
clearInterval(interval);
readStream();
controller.close();
});
},
pull(controller) {
// We don't really need a pull in this example
},
cancel() {
// This is called if the reader cancels,
// so we should stop generating strings
clearInterval(interval);
},
});
ì¤í¸ë¦¼ì ë£ì 문ìì´ ì ë¶ë¥¼ ì½ê³ ë¤ë£¨ê¸° ìí´ ë§ë 커ì¤í
í¨ìì¸ readStream() í¨ì를 ì´í´ë³´ë©´, ì°ì ReadableStream.getReader()를 ì¬ì©íì¬ ë¦¬ë기를 ì¤í¸ë¦¼ì ê³ ì ìí¤ë ê²ì ë³¼ì ììµëë¤. ê·¸ í ìì ì´í´ë´¤ë í¨í´ê³¼ ë§ì°¬ê°ì§ë¡ read() 를 ì¬ì©íì¬ chunk를 ì½ì´ ë¤ì´ê³ done ì´ true ì¸ì§ ìëì§ íì¸ í©ëë¤. ë§ì½ true ì´ë©´ readStream() í¨ìì íë¡ì¸ì¤ë¥¼ ëë´ë²ë¦¬ê³ ê·¸ë ì§ ìì¼ë©´ ì½ì´ë린 chunk를 íìì²ë¦¬í í read() 를 ì¬ê·ì ì¼ë¡ ì¤íí©ëë¤.
function readStream() {
const reader = stream.getReader();
let charsReceived = 0;
// read() returns a promise that resolves
// when a value has been received
reader.read().then(function processText({ done, value }) {
// Result objects contain two properties:
// done - true if the stream has already given you all its data.
// value - some data. Always undefined when done is true.
if (done) {
console.log("Stream complete");
para.textContent = result;
return;
}
charsReceived += value.length;
const chunk = value;
let listItem = document.createElement("li");
listItem.textContent =
"Read " + charsReceived + " characters so far. Current chunk = " + chunk;
list2.appendChild(listItem);
result += chunk;
// Read some more, and call this function again
return reader.read().then(processText);
});
}
Closing and cancelling streams
ì°ë¦¬ë ì´ë¯¸ ìì ì¤í¸ë¦¼ì ë«ë ë©ìëì¸ ReadableStreamDefaultController.close() 를 ì´í´ë³´ììµëë¤. ì´ë¯¸ ì¸ê¸íë¤ ìí¼, ì¤í¸ë¦¼ì´ ë«íë¤ íëë¼ê³ ì´ë¯¸ ë¤ì´ê° ìë chunkë ì½ì ì ììµëë¤.
ë§ì½ ì¤í¸ë¦¼ì ìë²½íê² ì ê±°íê³ ì½ì
ë 모ë chunk를 ë ë¦¬ê³ ì¶ë¤ë©´, ReadableStream.cancel() ëë ReadableStreamDefaultReader.cancel() ë©ìë를 ì¬ì© íë©´ ë©ëë¤.
Teeing a stream
ëë¡ë íëì ì¤í¸ë¦¼ì ëì ëë² ì½ì´ë¤ì¬ì¼ í ê²½ì°ê° ììµëë¤. ReadableStream.tee() ë©ìëê° ì´ë¥¼ ê°ë¥íê² í©ëë¤. ReadableStream.tee() ë©ìëë ëê°ì ë
립ì ì¸ ì¹´í¼ë ì¤í¸ë¦¼ì ê°ì§ê³ ìë ë°°ì´ì ì ê³µí©ëë¤. ì´ ì¹´í¼ë ëê°ì ì¤í¸ë¦¼ì ëê°ì ë
립ì ì¸ ë¦¬ëê¸°ë¡ ê°ê° ì½ì´ ë¤ì¼ ì ììµëë¤.
ì´ë° ê²½ì°ë ìë§ ServiceWorker ììì íìí ê²ì ëë¤. ë§ì½ ìë²ë¡ë¶í° fetchë response를 ë¸ë¼ì°ì ìë ì ë¬íê³ ìë¹ì¤ ì커 ìºììë ì ë¬í´ì¼ íë¤ë©´ íëì ì¤í¸ë¦¼ì ëí´ ëê°ì ì¹´í¼ë³¸ì´ íì í ê²ì ëë¤. ìëíë©´ response body (Readablestream)ë ë¨ íë²ë§ ì¬ì©ë ì ìê³ íëì Readablestreamì íëì 리ëê¸°ë§ ë¶ìì ì기 ë문ì ëë¤.
ì ë´ì©ì ëí ìì 를 Simple tee example (see it live also)ìì ì´í´ ë³¼ì ììµëë¤. ì´ ìì ë ëë¤ ë¬¸ìì´ ìì± ë²í¼ì ëí ì´ë²¤í¸ê° ìë¤ë ì ê³¼, ì´ ìì ììì ì¤í¸ë¦¼ì teedëì´ ëê°ì ì¤í¸ë¦¼ì´ ëê°ì 리ëê¸°ë¡ ì½ì´ì§ë¤ë ì ë§ ì ì¸íë©´ ìì ì´í´ë³¸ Simple random stream ìì ì ë§¤ì° ì ì¬íê² ëìí©ëë¤.
function teeStream() {
const teedOff = stream.tee();
readStream(teedOff[0], list2);
readStream(teedOff[1], list3);
}
Pipe chains
One very experimental feature of streams is the ability to pipe streams into one another (called a pipe chain). This involves two methods â ReadableStream.pipeThrough(), which pipes a readable stream through a writer/reader pair to transform one data format into another, and ReadableStream.pipeTo(), which pipes a readable stream to a writer acting as an end point for the pipe chain.
This functionality is at a very experimental stage and is subject to change, so we have no explored it too deeply as of yet.
We have created an example called Unpack Chunks of a PNG (see it live also) that fetches an image as a stream, then pipes it through to a custom PNG transform stream that retrieves PNG chunks out of a binary data stream.
// Fetch the original image
fetch("png-logo.png")
// Retrieve its body as ReadableStream
.then((response) => response.body)
// Create a gray-scaled PNG stream out of the original
.then((rs) => logReadableStream("Fetch Response Stream", rs))
.then((body) => body.pipeThrough(new PNGTransformStream()))
.then((rs) => logReadableStream("PNG Chunk Stream", rs));
Summary
That explains the basics of "default" readable streams. We'll explain bytestreams in a separate future article, once they are available in browsers.