How to Convert JavaScript ReadableStream Object to JSON?

You can convert a JavaScript ReadableStream object to JSON in the following ways:

  1. Using the Response.json() Method;
  2. Reading Streamed JSON Data in Chunks.

Using the Response.json() Method

If you're using the JavaScript fetch() api to make ajax calls, then the Response.body property is returned as ReadableStream object. To convert it to JSON, you can simply call the Response.json() method, for example, like so:

const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const jsonData = await response.json();

console.log(jsonData); // {...}

Using the Response.json() method reads the stream to completion and returns the parsed JSON data.

Please note that you must await the Response.json() method as it's async.

Reading Streamed JSON Data in Chunks

If you have a large incoming data stream as a response, then you can read it incrementally using the ReadableStream. This will allow you to read the data as it becomes available by consuming and processing it in chunks. This can then be converted to JSON. For example, one way you can do that is as follows:

async function toJSON(body) {
  const reader = body.getReader(); // `ReadableStreamDefaultReader`
  const decoder = new TextDecoder();
  const chunks = [];

  async function read() {
    const { done, value } = await reader.read();

    // all chunks have been read?
    if (done) {
      return JSON.parse(chunks.join(''));
    }

    const chunk = decoder.decode(value, { stream: true });
    chunks.push(chunk);
    return read(); // read the next chunk
  }

  return read();
}

const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const jsonData = await toJSON(response.body);

console.log(jsonData); // {...}

In this example:

  1. The ReadableStreamDefaultReader object, obtained from Response.body.getReader(), is used to read the stream incrementally;
  2. The TextDecoder.decode() method is called on the value property of the chunk to decode it into a string, and the resulting chunk is pushed into the "chunks" array;
  3. The read() function is called recursively until the done property of the chunk becomes true;
  4. When all chunks are read, they're joined together into a string using chunks.join('') and parsed as JSON using JSON.parse().

This approach can be useful in the following scenarios:

  • Memory Efficiency: When dealing with large JSON responses, this approach allows you to process the data in smaller, incremental chunks instead of loading the entire response into memory at once. This can significantly reduce memory usage, especially when dealing with large or streaming data.
  • Early Data Availability: With this approach, as soon as a chunk of data becomes available, you can start processing and consuming it. This can be beneficial in situations where you need to display or use the data in real-time while it is still being streamed. It provides early access to the data, improving responsiveness and user experience.
  • Progressive Loading: Parsing streamed JSON data in chunks enables progressive loading, where the data is displayed or processed as it arrives. This can be particularly useful when working with slow or unreliable network connections, as it allows you to show partial results or update the UI progressively as more data arrives.
  • Handling Large Data Sets: The approach is well-suited for handling large data sets that may not fit entirely in memory. By processing the data in smaller chunks, you can efficiently handle and manipulate large amounts of data without overwhelming system resources.

This post was published (and was last revised ) by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.