-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WritableStream Example #532
base: gh-pages
Are you sure you want to change the base?
Changes from all commits
6999962
f510a64
d4531c1
697d46b
82556eb
0a2cdd6
b979d69
8c134b3
4178473
04b705c
8eb3ecf
a9ee01f
0a1c194
6e46647
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,8 @@ | ||||
<!-- TODO: Replace PLACEHOLDER with feature name. --> | ||||
Stream Samples | ||||
=== | ||||
<!-- TODO: Replace PLACEHOLDER in the path to correspond to the real github.io URL. --> | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
See https://googlechrome.github.io/samples/streams/index.html for a live demo. | ||||
|
||||
<!-- TODO: Replace PLACEHOLDER with the id from the chromestatus.com URL. --> | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
Learn more at https://www.chromestatus.com/feature/5928498656968704 |
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,61 @@ | ||||||||||||||||||
'use strict'; | ||||||||||||||||||
|
||||||||||||||||||
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}); | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can these variables be const?
Comment on lines
+11
to
+14
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
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 | ||||||||||||||||||
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(() => { | ||||||||||||||||||
defaultWriter.close() | ||||||||||||||||||
.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: 1})); | ||||||||||||||||||
let message = document.querySelector('#input'); | ||||||||||||||||||
sendMessage(message.value); | ||||||||||||||||||
message.value = ""; | ||||||||||||||||||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
--- | ||
feature_name: WritableStream | ||
chrome_version: 59 | ||
feature_id: 5928498656968704 | ||
--- | ||
|
||
<h3>Background</h3> | ||
<p>This sample illustrates the use of <code><a href="https://streams.spec.whatwg.org/#ws">WritableStream</a></code>, which shows how to break apart a longer piece of data and stream it (send it in chunks) to an output.</p> | ||
|
||
<p>WritableStreams objects are designed to only be used once. This example creates a new instance every time "Send message" is clicked. The <code>sendMessage()</code> uses that instance to send every byte of the entered message and closes the instance when it is done (<code>defaultWriter.close()</code>).</p> | ||
|
||
<p>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.</p> | ||
|
||
<ol> | ||
<li>Create an instance of <code>WritableStream</code>. Pass it a data destination, called a 'sink' in it's constructor as a literal.</li> | ||
<li>Call <code>writableStreamInstance.getWriter()</code> to get a defaul writer.</li> | ||
<li>Iterate the chunks of the message and pass each to the default writer.</li> | ||
<li>Close the default writer.</li> | ||
</ol> | ||
|
||
<p>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.</p> | ||
|
||
<ul> | ||
<li><em><code>highwatermark</code>:</em> Specifies the maximum amout of data that the <code>WritableStream</code> can handle at once. When creating the <code>WritableStream</code> instance, the second property passed to the constructor is a queuing strategy object. This object's constructor takes an object with a <code>highwatermark</code> property. How <code>highwatermark</code> is specified varies depending on the type of queuing strategy object.</li> | ||
<li><em><code>writer.ready</code>: </em>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 <strong>and</strong> before closing the writer.</li> | ||
|
||
<li><em>The promise returned by <code>write()</code>:</em> The sink's <code>write()</code> method must return a promise. This tells <code>writer.ready()</code> when to return its promise.</li> | ||
</ul> | ||
|
||
{% capture initial_output_content %} | ||
|
||
<form id="sample-form"> | ||
<div> | ||
<label for="input">Enter a text message:</label> | ||
<input id="input" type="text"> | ||
|
||
</div> | ||
</form> | ||
<button id="sendMessage">Send message</button> | ||
{% endcapture %} | ||
{% include output_helper.html initial_output_content=initial_output_content %} | ||
|
||
{% include js_snippet.html filename='demo.js' %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove these TODOs?