Skip to content

Instantly share code, notes, and snippets.

@charlieforward9
Last active December 31, 2024 00:03
Show Gist options
  • Save charlieforward9/19b657747fb95d0e5a9d6b3cbdac23bd to your computer and use it in GitHub Desktop.
Save charlieforward9/19b657747fb95d0e5a9d6b3cbdac23bd to your computer and use it in GitHub Desktop.
Fetch with Progress callback

I had this in my new heat project but wasnt using it anymore and didnt want to just delete it or keep it in the codebase as a comment, so a gist it is.

export async function fetchWithProgress(
  url: string,
  onProgress?: (progress: number) => void
) {
  const response = await fetch(url);

  if (!response.ok) {
    throw new Error("Network response was not ok");
  }

  const contentLength = response.headers.get("Content-Length");
  if (!contentLength) {
    throw new Error("Content-Length response header is missing");
  }

  const total = parseInt(contentLength, 10);
  let loaded = 0;

  if (!response.body) {
    throw new Error("There is no body in this request");
  }

  const reader = response.body.getReader();
  const stream = new ReadableStream({
    start(controller) {
      function push() {
        reader
          .read()
          .then(({ done, value }) => {
            if (done) {
              controller.close();
              return;
            }

            loaded += value.byteLength;
            if (onProgress) onProgress((loaded / total) * 100);

            controller.enqueue(value);
            push();
          })
          .catch((error) => {
            console.error("Stream reading error:", error);
            controller.error(error);
          });
      }

      push();
    },
  });

  const newResponse = new Response(stream);
  const data = await newResponse.json(); 
  return data;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment