From 6999962d3ed12739c46c60189c23f5963318a2cd Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 27 Jul 2017 14:56:41 -0700 Subject: [PATCH 01/14] Create pages for WritableStream sample. --- streams-writable/README.md | 8 ++++++++ streams-writable/demo.js | 0 streams-writable/index.html | 30 ++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100755 streams-writable/README.md create mode 100644 streams-writable/demo.js create mode 100755 streams-writable/index.html diff --git a/streams-writable/README.md b/streams-writable/README.md new file mode 100755 index 0000000000..6f6f47321f --- /dev/null +++ b/streams-writable/README.md @@ -0,0 +1,8 @@ + +PLACEHOLDER Sample +=== + +See https://googlechrome.github.io/samples/PLACEHOLDER/index.html for a live demo. + + +Learn more at https://www.chromestatus.com/feature/PLACEHOLDER diff --git a/streams-writable/demo.js b/streams-writable/demo.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/streams-writable/index.html b/streams-writable/index.html new file mode 100755 index 0000000000..0e3b6d753c --- /dev/null +++ b/streams-writable/index.html @@ -0,0 +1,30 @@ +--- +feature_name: WritableStream +chrome_version: WritableStream +feature_id: 5928498656968704 +local_css_files: ['optional_relative_path.css', 'anotheroptional_relative_path.css'] +local_js_files: ['optional_relative_path.js', 'anotheroptional_relative_path.js'] +additional_head_content: +--- + +

Background

+

Background info goes here.

+

Any content here, outside of a capture block, is included verbatim on the resulting page.

+ +{% capture initial_output_content %} +

This optional capture/include can be used to set initial sample output.

+{% endcapture %} +{% include output_helper.html initial_output_content=initial_output_content %} + +/* + Use this optional include for any JavaScript that shows off the feature's functionality. + Do not surround it with <script> tags. + If output_helper.html is included on this page, then ChromeSamples.log(), + ChromeSamples.clearLog(), ChromeSamples.setStatus(), and ChromeSamples.setContent() can be used. +*/ +{% include js_snippet.html filename='demo.js' %} + +{% capture css %} +/* Use this optional capture/include for CSS that shows off the feature's functionality. */ +{% endcapture %} +{% include css_snippet.html css=css %} From f510a6412d6d41e82f4f65e72a69d9899b78e19b Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 27 Jul 2017 19:27:15 -0700 Subject: [PATCH 02/14] First pass at WritableStream sample. --- streams-writable/demo.js | 44 +++++++++++++++++++++++++++++++++++++ streams-writable/index.html | 8 ------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/streams-writable/demo.js b/streams-writable/demo.js index e69de29bb2..da0b1925aa 100644 --- a/streams-writable/demo.js +++ b/streams-writable/demo.js @@ -0,0 +1,44 @@ +'use strict'; + +const sink = { + result: "", + write(chunk) { + this.result += String.fromCharCode(parseInt(chunk, 10)); + }, + close() { + ChromeSamples.log(this.result); + }, + abort(e) { + ChromeSamples.log("[SINK] Error: " + e); + } +} + +const ws = new WritableStream(sink); +var msgArray = buffer("[STREAMED CONTENT]: This is only a test."); +textToStream(msgArray, ws) + .then(() => ChromeSamples.log("All chunks written. Stream closed.")) + .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); + +function buffer(string) { + var utf8 = unescape(encodeURIComponent(string)); + + var arr = []; + for (var i = 0; i < utf8.length; i++) { + arr.push(utf8.charCodeAt(i)); + } + return arr; +} + +function textToStream(buffer, writableStream) { + var writer = writableStream.getWriter(); + buffer.forEach(chunk => { + writer.write(chunk) + .then(() => { + ChromeSamples.log("Chunk written to sink."); + }) + .catch(e => { + ChromeSamples.log("[CHUNK] Error: " + e); + }); + }); + return writer.close(); +} diff --git a/streams-writable/index.html b/streams-writable/index.html index 0e3b6d753c..0d3873983b 100755 --- a/streams-writable/index.html +++ b/streams-writable/index.html @@ -2,9 +2,6 @@ feature_name: WritableStream chrome_version: WritableStream feature_id: 5928498656968704 -local_css_files: ['optional_relative_path.css', 'anotheroptional_relative_path.css'] -local_js_files: ['optional_relative_path.js', 'anotheroptional_relative_path.js'] -additional_head_content: ---

Background

@@ -23,8 +20,3 @@

Background

ChromeSamples.clearLog(), ChromeSamples.setStatus(), and ChromeSamples.setContent() can be used. */ {% include js_snippet.html filename='demo.js' %} - -{% capture css %} -/* Use this optional capture/include for CSS that shows off the feature's functionality. */ -{% endcapture %} -{% include css_snippet.html css=css %} From d4531c1d9eef6f63a22b5c2fe7077149c53ae453 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 12:07:41 -0700 Subject: [PATCH 03/14] Feedback from Jake. --- streams-writable/demo.js | 47 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/streams-writable/demo.js b/streams-writable/demo.js index da0b1925aa..cf94a5b8d4 100644 --- a/streams-writable/demo.js +++ b/streams-writable/demo.js @@ -1,44 +1,37 @@ 'use strict'; -const sink = { - result: "", +let result = ""; +const decoder = new TextDecoder("utf-8"); +const writable = new WritableStream({ write(chunk) { - this.result += String.fromCharCode(parseInt(chunk, 10)); + let buffer = new ArrayBuffer(2); + let view = new Uint16Array(buffer); + view[0] = chunk; + let decoded = decoder.decode(view, {stream: true}); + ChromeSamples.log(decoded); + result += decoded }, close() { - ChromeSamples.log(this.result); + ChromeSamples.log(result); }, abort(e) { ChromeSamples.log("[SINK] Error: " + e); } -} +}); -const ws = new WritableStream(sink); -var msgArray = buffer("[STREAMED CONTENT]: This is only a test."); -textToStream(msgArray, ws) +const message = "[STREAMED CONTENT]: This is only a test."; +textToStream(message, writable) .then(() => ChromeSamples.log("All chunks written. Stream closed.")) .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); -function buffer(string) { - var utf8 = unescape(encodeURIComponent(string)); - - var arr = []; - for (var i = 0; i < utf8.length; i++) { - arr.push(utf8.charCodeAt(i)); - } - return arr; -} - -function textToStream(buffer, writableStream) { - var writer = writableStream.getWriter(); - buffer.forEach(chunk => { +function textToStream(message, writableStream) { + const writer = writableStream.getWriter(); + const encoder = new TextEncoder(); + const encoded = encoder.encode(message, {stream: true}); + encoded.forEach(chunk => { writer.write(chunk) - .then(() => { - ChromeSamples.log("Chunk written to sink."); - }) - .catch(e => { - ChromeSamples.log("[CHUNK] Error: " + e); - }); + .then(() => ChromeSamples.log("Chunk written to sink.")) + .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); }); return writer.close(); } From 697d46bfc8a5c5bab254b42893a2ce17bd7269cb Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 13:56:26 -0700 Subject: [PATCH 04/14] Rename streams folder. --- streams-writable/index.html | 22 --------------------- {streams-writable => streams}/README.md | 0 {streams-writable => streams}/demo.js | 26 +++++++++++++++---------- streams/index.html | 23 ++++++++++++++++++++++ 4 files changed, 39 insertions(+), 32 deletions(-) delete mode 100755 streams-writable/index.html rename {streams-writable => streams}/README.md (100%) rename {streams-writable => streams}/demo.js (54%) create mode 100755 streams/index.html diff --git a/streams-writable/index.html b/streams-writable/index.html deleted file mode 100755 index 0d3873983b..0000000000 --- a/streams-writable/index.html +++ /dev/null @@ -1,22 +0,0 @@ ---- -feature_name: WritableStream -chrome_version: WritableStream -feature_id: 5928498656968704 ---- - -

Background

-

Background info goes here.

-

Any content here, outside of a capture block, is included verbatim on the resulting page.

- -{% capture initial_output_content %} -

This optional capture/include can be used to set initial sample output.

-{% endcapture %} -{% include output_helper.html initial_output_content=initial_output_content %} - -/* - Use this optional include for any JavaScript that shows off the feature's functionality. - Do not surround it with <script> tags. - If output_helper.html is included on this page, then ChromeSamples.log(), - ChromeSamples.clearLog(), ChromeSamples.setStatus(), and ChromeSamples.setContent() can be used. -*/ -{% include js_snippet.html filename='demo.js' %} diff --git a/streams-writable/README.md b/streams/README.md similarity index 100% rename from streams-writable/README.md rename to streams/README.md diff --git a/streams-writable/demo.js b/streams/demo.js similarity index 54% rename from streams-writable/demo.js rename to streams/demo.js index cf94a5b8d4..977f06a442 100644 --- a/streams-writable/demo.js +++ b/streams/demo.js @@ -8,10 +8,11 @@ const writable = new WritableStream({ let view = new Uint16Array(buffer); view[0] = chunk; let decoded = decoder.decode(view, {stream: true}); - ChromeSamples.log(decoded); + ChromeSamples.log("Chunk decoded: " + decoded); result += decoded }, close() { + result = "[MESSAGE RECEIVED] " + result; ChromeSamples.log(result); }, abort(e) { @@ -19,19 +20,24 @@ const writable = new WritableStream({ } }); -const message = "[STREAMED CONTENT]: This is only a test."; -textToStream(message, writable) - .then(() => ChromeSamples.log("All chunks written. Stream closed.")) - .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); - -function textToStream(message, writableStream) { - const writer = writableStream.getWriter(); +function sendMessage(message) { + const writer = writable.getWriter(); const encoder = new TextEncoder(); const encoded = encoder.encode(message, {stream: true}); encoded.forEach(chunk => { writer.write(chunk) - .then(() => ChromeSamples.log("Chunk written to sink.")) + .then(() => ChromeSamples.log("Chunk written to sink. 'writer.write()` promise resolved.")) .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); }); - return writer.close(); + writer.close() + .then(() => ChromeSamples.log("All chunks written. 'writer.close()` promise resolved.")) + .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); } + + +document.querySelector('#sendMessage').addEventListener('click', function() { + ChromeSamples.clearLog(); + let entry = document.querySelector('#input'); + passStream(entry.value); + entry.value = ""; +}); \ No newline at end of file diff --git a/streams/index.html b/streams/index.html new file mode 100755 index 0000000000..f4527bfbb1 --- /dev/null +++ b/streams/index.html @@ -0,0 +1,23 @@ +--- +feature_name: WritableStream +chrome_version: WritableStream +feature_id: 5928498656968704 +--- + +

Background

+

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output.

+ +{% capture initial_output_content %} + +
+
+ + + +
+
+ +{% endcapture %} +{% include output_helper.html initial_output_content=initial_output_content %} + +{% include js_snippet.html filename='demo.js' %} From 82556ebca55370705a1afcebfaf3e3b52c54836f Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 13:57:52 -0700 Subject: [PATCH 05/14] Fill out README. --- streams/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/streams/README.md b/streams/README.md index 6f6f47321f..3d51f13a6d 100755 --- a/streams/README.md +++ b/streams/README.md @@ -1,8 +1,8 @@ -PLACEHOLDER Sample +Stream Samples === -See https://googlechrome.github.io/samples/PLACEHOLDER/index.html for a live demo. +See https://googlechrome.github.io/samples/streams/index.html for a live demo. -Learn more at https://www.chromestatus.com/feature/PLACEHOLDER +Learn more at https://www.chromestatus.com/feature/5928498656968704 From 0a2cdd63703e112586b66bb28736f06d74292d9a Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 13:59:29 -0700 Subject: [PATCH 06/14] Fix indentation. --- streams/index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/streams/index.html b/streams/index.html index f4527bfbb1..0b4f53f5fe 100755 --- a/streams/index.html +++ b/streams/index.html @@ -10,11 +10,11 @@

Background

{% capture initial_output_content %}
-
- - - -
+
+ + + +
{% endcapture %} From b979d6905cc0a1e69b18d337af37b79de4cc8aed Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 14:15:11 -0700 Subject: [PATCH 07/14] Fix errors. --- streams/demo.js | 2 +- streams/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/streams/demo.js b/streams/demo.js index 977f06a442..33ac46b983 100644 --- a/streams/demo.js +++ b/streams/demo.js @@ -38,6 +38,6 @@ function sendMessage(message) { document.querySelector('#sendMessage').addEventListener('click', function() { ChromeSamples.clearLog(); let entry = document.querySelector('#input'); - passStream(entry.value); + sendMessage(entry.value); entry.value = ""; }); \ No newline at end of file diff --git a/streams/index.html b/streams/index.html index 0b4f53f5fe..a325afeb47 100755 --- a/streams/index.html +++ b/streams/index.html @@ -5,7 +5,7 @@ ---

Background

-

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output.

+

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output. This example is intended as a first step to understanding streams.

{% capture initial_output_content %} From 8c134b30c92da706939bf46869e6bfd51983e4b2 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 20:28:49 -0700 Subject: [PATCH 08/14] Fix chorme_version. --- streams/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/streams/index.html b/streams/index.html index a325afeb47..29f44661c7 100755 --- a/streams/index.html +++ b/streams/index.html @@ -1,6 +1,6 @@ --- feature_name: WritableStream -chrome_version: WritableStream +chrome_version: 59 feature_id: 5928498656968704 --- From 4178473afe5dfc6233890e7c586400fe7a89efa7 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Thu, 3 Aug 2017 21:07:25 -0700 Subject: [PATCH 09/14] Add more stuff from the spec. --- streams/demo.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/streams/demo.js b/streams/demo.js index 33ac46b983..fac3964630 100644 --- a/streams/demo.js +++ b/streams/demo.js @@ -21,17 +21,21 @@ const writable = new WritableStream({ }); function sendMessage(message) { - const writer = writable.getWriter(); + // defaultWriter is of type WritableStreamDefaultWriter + const defaultWriter = writable.getWriter(); const encoder = new TextEncoder(); const encoded = encoder.encode(message, {stream: true}); - encoded.forEach(chunk => { - writer.write(chunk) - .then(() => ChromeSamples.log("Chunk written to sink. 'writer.write()` promise resolved.")) - .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + defaultWriter.ready + .then(() => { + encoded.forEach(chunk => { + defaultWriter.write(chunk) + .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) + .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + }); + defaultWriter.close() + .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()` promise resolved.")) + .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); }); - writer.close() - .then(() => ChromeSamples.log("All chunks written. 'writer.close()` promise resolved.")) - .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); } From 04b705cc043a85aebc3ffdbf620dc044f8f55d14 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Fri, 4 Aug 2017 10:57:20 -0700 Subject: [PATCH 10/14] Backpressure, take I. --- streams/demo.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/streams/demo.js b/streams/demo.js index fac3964630..23dc3a350d 100644 --- a/streams/demo.js +++ b/streams/demo.js @@ -3,13 +3,17 @@ let result = ""; const decoder = new TextDecoder("utf-8"); const writable = new WritableStream({ + // Implement the sink write(chunk) { - let buffer = new ArrayBuffer(2); - let view = new Uint16Array(buffer); - view[0] = chunk; - let decoded = decoder.decode(view, {stream: true}); - ChromeSamples.log("Chunk decoded: " + decoded); - result += decoded + return new Promise((resolve, reject) => { + let buffer = new ArrayBuffer(2); + let view = new Uint16Array(buffer); + view[0] = chunk; + let decoded = decoder.decode(view, {stream: true}); + ChromeSamples.log("Chunk decoded: " + decoded); + result += decoded + resolve(); + }); }, close() { result = "[MESSAGE RECEIVED] " + result; @@ -18,7 +22,7 @@ const writable = new WritableStream({ abort(e) { ChromeSamples.log("[SINK] Error: " + e); } -}); +}, new CountQueuingStrategy({highWaterMark: 2})); function sendMessage(message) { // defaultWriter is of type WritableStreamDefaultWriter @@ -28,9 +32,11 @@ function sendMessage(message) { defaultWriter.ready .then(() => { encoded.forEach(chunk => { - defaultWriter.write(chunk) - .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) - .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + if ((defaultWriter.desiredSize != null) && (defaultWriter.desiredSize != 0)) { + defaultWriter.write(chunk) + .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) + .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + } }); defaultWriter.close() .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()` promise resolved.")) From 8eb3ecf309e5b6155e636442639d56e831e6454f Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Fri, 4 Aug 2017 13:14:47 -0700 Subject: [PATCH 11/14] Create new writer every time. --- streams/demo.js | 61 ++++++++++++++++++++++++++----------------------- streams/temp.js | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 streams/temp.js diff --git a/streams/demo.js b/streams/demo.js index 23dc3a350d..b54fa1dcb0 100644 --- a/streams/demo.js +++ b/streams/demo.js @@ -1,28 +1,31 @@ 'use strict'; -let result = ""; -const decoder = new TextDecoder("utf-8"); -const writable = new WritableStream({ - // Implement the sink - write(chunk) { - return new Promise((resolve, reject) => { - let buffer = new ArrayBuffer(2); - let view = new Uint16Array(buffer); - view[0] = chunk; - let decoded = decoder.decode(view, {stream: true}); - ChromeSamples.log("Chunk decoded: " + decoded); - result += decoded - resolve(); - }); - }, - close() { - result = "[MESSAGE RECEIVED] " + result; - ChromeSamples.log(result); - }, - abort(e) { - ChromeSamples.log("[SINK] Error: " + e); - } -}, new CountQueuingStrategy({highWaterMark: 2})); +let result; +function getWritableStream(queuingStrategy) { + const decoder = new TextDecoder("utf-8"); + result = ""; + return new WritableStream({ + // Implement the sink + write(chunk) { + return new Promise((resolve, reject) => { + let buffer = new ArrayBuffer(2); + let view = new Uint16Array(buffer); + view[0] = chunk; + let decoded = decoder.decode(view, {stream: true}); + ChromeSamples.log("Chunk decoded: " + decoded); + result += decoded + resolve(); + }); + }, + close() { + result = "[MESSAGE RECEIVED] " + result; + ChromeSamples.log(result); + }, + abort(e) { + ChromeSamples.log("[SINK] Error: " + e); + } + }, queuingStrategy); +} function sendMessage(message) { // defaultWriter is of type WritableStreamDefaultWriter @@ -44,10 +47,12 @@ function sendMessage(message) { }); } - +let writable; document.querySelector('#sendMessage').addEventListener('click', function() { ChromeSamples.clearLog(); - let entry = document.querySelector('#input'); - sendMessage(entry.value); - entry.value = ""; -}); \ No newline at end of file + // Streams are only meant be used once. Get a stream for each message. + writable = getWritableStream(new CountQueuingStrategy({highWaterMark: 2})); + let message = document.querySelector('#input'); + sendMessage(message.value); + message.value = ""; +}) \ No newline at end of file diff --git a/streams/temp.js b/streams/temp.js new file mode 100644 index 0000000000..23dc3a350d --- /dev/null +++ b/streams/temp.js @@ -0,0 +1,53 @@ +'use strict'; + +let result = ""; +const decoder = new TextDecoder("utf-8"); +const writable = new WritableStream({ + // Implement the sink + write(chunk) { + return new Promise((resolve, reject) => { + let buffer = new ArrayBuffer(2); + let view = new Uint16Array(buffer); + view[0] = chunk; + let decoded = decoder.decode(view, {stream: true}); + ChromeSamples.log("Chunk decoded: " + decoded); + result += decoded + resolve(); + }); + }, + close() { + result = "[MESSAGE RECEIVED] " + result; + ChromeSamples.log(result); + }, + abort(e) { + ChromeSamples.log("[SINK] Error: " + e); + } +}, new CountQueuingStrategy({highWaterMark: 2})); + +function sendMessage(message) { + // defaultWriter is of type WritableStreamDefaultWriter + const defaultWriter = writable.getWriter(); + const encoder = new TextEncoder(); + const encoded = encoder.encode(message, {stream: true}); + defaultWriter.ready + .then(() => { + encoded.forEach(chunk => { + if ((defaultWriter.desiredSize != null) && (defaultWriter.desiredSize != 0)) { + defaultWriter.write(chunk) + .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) + .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + } + }); + defaultWriter.close() + .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()` promise resolved.")) + .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); + }); +} + + +document.querySelector('#sendMessage').addEventListener('click', function() { + ChromeSamples.clearLog(); + let entry = document.querySelector('#input'); + sendMessage(entry.value); + entry.value = ""; +}); \ No newline at end of file From a9ee01f105e62765614d508f5d534c0058325702 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Fri, 4 Aug 2017 15:21:42 -0700 Subject: [PATCH 12/14] Get the order correct. --- streams/demo.js | 21 +++++++++++--------- streams/temp.js | 53 ------------------------------------------------- 2 files changed, 12 insertions(+), 62 deletions(-) delete mode 100644 streams/temp.js diff --git a/streams/demo.js b/streams/demo.js index b54fa1dcb0..c65eef18d1 100644 --- a/streams/demo.js +++ b/streams/demo.js @@ -32,26 +32,29 @@ function sendMessage(message) { const defaultWriter = writable.getWriter(); const encoder = new TextEncoder(); const encoded = encoder.encode(message, {stream: true}); + encoded.forEach(chunk => { + defaultWriter.ready + .then(() => { + defaultWriter.write(chunk) + .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()' promise resolved.")) + .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); + }); + }) + // Calling ready insures that all chunks are written to the sink before the writer is closed. defaultWriter.ready .then(() => { - encoded.forEach(chunk => { - if ((defaultWriter.desiredSize != null) && (defaultWriter.desiredSize != 0)) { - defaultWriter.write(chunk) - .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) - .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); - } - }); defaultWriter.close() - .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()` promise resolved.")) + .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()' promise resolved.")) .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); }); } let writable; document.querySelector('#sendMessage').addEventListener('click', function() { + // Clear the output from the previous call to sendMessage(). ChromeSamples.clearLog(); // Streams are only meant be used once. Get a stream for each message. - writable = getWritableStream(new CountQueuingStrategy({highWaterMark: 2})); + writable = getWritableStream(new CountQueuingStrategy({highWaterMark: 1})); let message = document.querySelector('#input'); sendMessage(message.value); message.value = ""; diff --git a/streams/temp.js b/streams/temp.js deleted file mode 100644 index 23dc3a350d..0000000000 --- a/streams/temp.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -let result = ""; -const decoder = new TextDecoder("utf-8"); -const writable = new WritableStream({ - // Implement the sink - write(chunk) { - return new Promise((resolve, reject) => { - let buffer = new ArrayBuffer(2); - let view = new Uint16Array(buffer); - view[0] = chunk; - let decoded = decoder.decode(view, {stream: true}); - ChromeSamples.log("Chunk decoded: " + decoded); - result += decoded - resolve(); - }); - }, - close() { - result = "[MESSAGE RECEIVED] " + result; - ChromeSamples.log(result); - }, - abort(e) { - ChromeSamples.log("[SINK] Error: " + e); - } -}, new CountQueuingStrategy({highWaterMark: 2})); - -function sendMessage(message) { - // defaultWriter is of type WritableStreamDefaultWriter - const defaultWriter = writable.getWriter(); - const encoder = new TextEncoder(); - const encoded = encoder.encode(message, {stream: true}); - defaultWriter.ready - .then(() => { - encoded.forEach(chunk => { - if ((defaultWriter.desiredSize != null) && (defaultWriter.desiredSize != 0)) { - defaultWriter.write(chunk) - .then(() => ChromeSamples.log("Chunk written to sink. 'defaultWriter.write()` promise resolved.")) - .catch(e => ChromeSamples.log("[CHUNK] Error: " + e)); - } - }); - defaultWriter.close() - .then(() => ChromeSamples.log("All chunks written. 'defaultWriter.close()` promise resolved.")) - .catch(e => ChromeSamples.log("[STREAM] Error: " + e)); - }); -} - - -document.querySelector('#sendMessage').addEventListener('click', function() { - ChromeSamples.clearLog(); - let entry = document.querySelector('#input'); - sendMessage(entry.value); - entry.value = ""; -}); \ No newline at end of file From 0a1c194b626cf4dbd7bdf95cc4fca28f6df5f53e Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Fri, 4 Aug 2017 19:10:17 -0700 Subject: [PATCH 13/14] Draft the explanation. --- streams/index.html | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/streams/index.html b/streams/index.html index 29f44661c7..bbfd70f7fb 100755 --- a/streams/index.html +++ b/streams/index.html @@ -5,7 +5,21 @@ ---

Background

-

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output. This example is intended as a first step to understanding streams.

+

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output.

+ +

WritableStreams objects are designed to only be used once. This example creates a new instance every time "Send message" is clicked. The sendMessage() uses that instance to send very byte of the entered message and closes the instance when it is done (defaultWriter.close()).

+ +

Data source > writer > sink

+ +

The writer is created by the WritableStream object.

+ +

If you're familliar at all with streams you may be wondering how backpressure is implemented using this API, especially since the word 'backpressure' doesn't appear as a member of any of the API's interfaces. Three items combine to create a backpressure signal.

+ +
    +
  • highwatermark: When creating the WritableStream instance, the second property passed to the constructor is a queuing strategy object. This object's constructor takes an object with a highwatermark property whose value species the maximum amount of data that the WritableStream can handle at once.
  • +
  • writer.ready: This tells you whether the underlying sink is done writing the data it's received. Check this before adding new data to the pipe and before closing the writer.
  • +
  • The promise returned by write(): The sink's write() method must return a promise. This is used to set writer.ready() to an appropriate value.
  • +
{% capture initial_output_content %} From 6e466473e16d152197fb8890af312409442ff310 Mon Sep 17 00:00:00 2001 From: Joseph Medley Date: Mon, 7 Aug 2017 15:26:03 -0700 Subject: [PATCH 14/14] Improve explanation draft. --- streams/index.html | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/streams/index.html b/streams/index.html index bbfd70f7fb..d372552abe 100755 --- a/streams/index.html +++ b/streams/index.html @@ -7,18 +7,24 @@

Background

This sample illustrates the use of WritableStream, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output.

-

WritableStreams objects are designed to only be used once. This example creates a new instance every time "Send message" is clicked. The sendMessage() uses that instance to send very byte of the entered message and closes the instance when it is done (defaultWriter.close()).

+

WritableStreams objects are designed to only be used once. This example creates a new instance every time "Send message" is clicked. The sendMessage() uses that instance to send every byte of the entered message and closes the instance when it is done (defaultWriter.close()).

-

Data source > writer > sink

+

The data flow in this example is generally from the text entry field to sink. The details are a bit more complicated. The general flow is this.

-

The writer is created by the WritableStream object.

+
    +
  1. Create an instance of WritableStream. Pass it a data destination, called a 'sink' in it's constructor as a literal.
  2. +
  3. Call writableStreamInstance.getWriter() to get a defaul writer.
  4. +
  5. Iterate the chunks of the message and pass each to the default writer.
  6. +
  7. Close the default writer.
  8. +

If you're familliar at all with streams you may be wondering how backpressure is implemented using this API, especially since the word 'backpressure' doesn't appear as a member of any of the API's interfaces. Three items combine to create a backpressure signal.

    -
  • highwatermark: When creating the WritableStream instance, the second property passed to the constructor is a queuing strategy object. This object's constructor takes an object with a highwatermark property whose value species the maximum amount of data that the WritableStream can handle at once.
  • -
  • writer.ready: This tells you whether the underlying sink is done writing the data it's received. Check this before adding new data to the pipe and before closing the writer.
  • -
  • The promise returned by write(): The sink's write() method must return a promise. This is used to set writer.ready() to an appropriate value.
  • +
  • highwatermark: Specifies the maximum amout of data that the WritableStream can handle at once. When creating the WritableStream instance, the second property passed to the constructor is a queuing strategy object. This object's constructor takes an object with a highwatermark property. How highwatermark is specified varies depending on the type of queuing strategy object.
  • +
  • writer.ready: Returns a promise that resolves whenever the underlying data sink is able to receive more data for writing. Check this before adding new data to the pipe and before closing the writer.
  • + +
  • The promise returned by write(): The sink's write() method must return a promise. This tells writer.ready() when to return its promise.
{% capture initial_output_content %}