0
0
DenoHow-ToBeginner ยท 4 min read

How to Use Streams API in Deno: Syntax and Examples

In Deno, you use the Streams API to handle data flow efficiently by working with ReadableStream and WritableStream. You create streams, read chunks asynchronously with getReader(), and write data using WritableStream methods. This lets you process data piece-by-piece without loading everything into memory.
๐Ÿ“

Syntax

The Streams API in Deno uses ReadableStream to read data and WritableStream to write data. You get a reader from a readable stream using getReader(), then read chunks asynchronously with read(). For writing, you use a WritableStream and its getWriter() method to write chunks.

Key parts:

  • ReadableStream: source of data you can read chunk by chunk.
  • WritableStream: destination where you can write data chunk by chunk.
  • getReader(): gets a reader to pull data from a readable stream.
  • read(): asynchronously reads the next chunk from the stream.
  • getWriter(): gets a writer to send data to a writable stream.
typescript
const readable = new ReadableStream({
  start(controller) {
    controller.enqueue(new TextEncoder().encode('Hello, '));
    controller.enqueue(new TextEncoder().encode('Deno Streams!'));
    controller.close();
  }
});

const reader = readable.getReader();

async function readStream() {
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    console.log(new TextDecoder().decode(value));
  }
}

readStream();
Output
Hello, Deno Streams!
๐Ÿ’ป

Example

This example shows how to create a ReadableStream that emits text chunks, read them asynchronously, and then write them to a WritableStream that collects the data into a string.

typescript
const readable = new ReadableStream({
  start(controller) {
    controller.enqueue(new TextEncoder().encode('Hello, '));
    controller.enqueue(new TextEncoder().encode('Streams API in Deno!'));
    controller.close();
  }
});

let collected = '';

const writable = new WritableStream({
  write(chunk) {
    collected += new TextDecoder().decode(chunk);
  },
  close() {
    console.log('Collected output:', collected);
  }
});

async function processStreams() {
  const reader = readable.getReader();
  const writer = writable.getWriter();

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    await writer.write(value);
  }

  await writer.close();
}

processStreams();
Output
Collected output: Hello, Streams API in Deno!
โš ๏ธ

Common Pitfalls

Common mistakes when using Streams API in Deno include:

  • Not awaiting read() or write() calls, causing unexpected behavior.
  • Forgetting to close streams, which can leave them hanging and cause resource leaks.
  • Trying to read from a stream after it is closed, which returns done: true immediately.
  • Mixing synchronous and asynchronous code without proper await, leading to race conditions.
typescript
/* Wrong: Not awaiting read() */
async function wrongRead(reader) {
  const result = reader.read(); // Missing await
  console.log(result); // Logs a Promise, not data
}

/* Right: Await read() */
async function rightRead(reader) {
  const result = await reader.read();
  console.log(result); // Logs { done: false, value: ... }
}
๐Ÿ“Š

Quick Reference

Method/PropertyDescription
ReadableStream.getReader()Returns a reader to read chunks from the stream.
ReadableStreamDefaultReader.read()Asynchronously reads the next chunk; returns { done, value }.
WritableStream.getWriter()Returns a writer to write chunks to the stream.
WritableStreamDefaultWriter.write(chunk)Writes a chunk to the stream asynchronously.
WritableStreamDefaultWriter.close()Closes the writable stream.
ReadableStream.close()Closes the readable stream, signaling no more data.
โœ…

Key Takeaways

Use getReader() and read() to consume data from a ReadableStream asynchronously.
Use getWriter() and write() to send data to a WritableStream.
Always await asynchronous stream operations to avoid bugs.
Close streams properly to free resources and signal completion.
Streams let you process data piece-by-piece without loading everything into memory.