Master WritableStream: Real-World Uses, Best Practices, and Common Pitfalls
This article introduces the JavaScript WritableStream API, explains its core methods and construction, demonstrates practical scenarios such as file uploads, logging, data transformation, and media handling, and discusses advanced considerations like chunk sizing, error recovery, concurrency control, and performance optimization.
What is WritableStream?
WritableStream is a Web API that lets developers write data to a destination such as a file, network connection, or any other sink without loading all data into memory at once. It includes built‑in back‑pressure handling and queuing.
Basic Steps
Create a WritableStream instance using new WritableStream() .
Write data with the write() method.
Close the stream using close() when writing is finished.
Handle errors with catch() or the abort() method.
<code>const writableStream = new WritableStream({
start(controller) {
// initialization logic
},
write(chunk, controller) {
console.log(`Writing chunk: ${chunk}`);
},
close(controller) {
console.log('Stream closed');
},
abort(reason) {
console.error(`Stream aborted: ${reason}`);
}
});</code>Constructor and Underlying Sink
The constructor can be called as new WritableStream(underlyingSink) or new WritableStream(underlyingSink, queuingStrategy) . The underlyingSink object defines the stream’s behavior with the following methods:
start(controller) : Called immediately after construction; can be async and receives a WritableStreamDefaultController .
write(chunk, controller) : Writes a data chunk; may be async.
close(controller) : Called after all writes are complete; may be async.
abort(reason) : Immediately aborts the stream, discarding pending chunks.
The optional queuingStrategy can specify highWaterMark (maximum queued chunks before back‑pressure) and size(chunk) (byte size of each chunk).
Common Methods
abort() : Terminates the stream and discards queued data.
close() : Closes the associated stream after pending writes finish.
getWriter() : Returns a WritableStreamDefaultWriter and locks the stream for exclusive writing.
Practical Use Cases
1. File Upload
<code>// Create a WritableStream for file upload
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', async (event) => {
const file = event.target.files[0];
const writableStream = new WritableStream({
write(chunk) {
fetch('/upload', { method: 'POST', body: chunk });
},
close() { console.log('Upload complete'); },
error(err) { console.error('Upload failed:', err); }
});
const reader = file.stream();
reader.pipeTo(writableStream);
});</code>2. Real‑time Logging
<code>const logStream = new WritableStream({
write(chunk) { console.log(chunk); }
});
function logMessage(msg) { logStream.write(msg + '\n'); }
logMessage('User visited page');</code>3. Data Transformation
<code>const transformStream = new WritableStream({
write(chunk) {
const str = JSON.stringify(chunk);
console.log(str);
}
});
const jsonData = { key: 'value' };
transformStream.write(jsonData);
</code>4. Audio/Video Stream Handling
<code>const audioContext = new AudioContext();
const audioStream = new WritableStream({
write(chunk) {
const source = audioContext.createBufferSource();
source.buffer = chunk; // chunk is an AudioBuffer
source.connect(audioContext.destination);
source.start();
}
});
audioStream.write(audioData);
</code>Advanced Considerations
Choosing chunk size : No universal formula; use performance testing and the stream’s desiredSize property to adapt dynamically.
Stream state checks : Verify writableStream.locked before writing; avoid writing to a closed or locked stream.
Concurrency control : Serialize writes using a queue or lock mechanism to preserve order in high‑concurrency scenarios.
Error recovery : Implement retry logic with a maximum attempt count and fallback strategies.
Buffering for performance : Accumulate small writes in a buffer and flush when a threshold is reached to reduce overhead.
Conclusion
WritableStream provides a flexible, efficient way to handle data writing in web applications. By understanding its API, common patterns, and potential pitfalls, developers can build robust solutions for file uploads, logging, data transformation, and media processing.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.