Show a Progress Indicator for a Fetch Request with the Streams API

AnthumChris collected some JavaScript scripts to track the progress of fetch requests that download files/data. It works by leveraging the ReadableStream interface from the Streams API.

A “simple” example is this:

fetch('https://fetch-progress.anthum.com/30kbps/images/sunrise-baseline.jpg')
.then(response => {
  if (!response.ok) {
    throw Error(response.status+' '+response.statusText)
  }

  if (!response.body) {
    throw Error('ReadableStream not yet supported in this browser.')
  }

  // to access headers, server must send CORS header "Access-Control-Expose-Headers: content-encoding, content-length x-file-size"
  // server must send custom x-file-size header if gzip or other content-encoding is used
  const contentEncoding = response.headers.get('content-encoding');
  const contentLength = response.headers.get(contentEncoding ? 'x-file-size' : 'content-length');
  if (contentLength === null) {
    throw Error('Response size header unavailable');
  }

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

  return new Response(
    new ReadableStream({
      start(controller) {
        const reader = response.body.getReader();

        read();
        function read() {
          reader.read().then(({done, value}) => {
            if (done) {
              controller.close();
              return; 
            }
            loaded += value.byteLength;
            console.log(Math.round(loaded/total*100)+'%');
            controller.enqueue(value);
            read();
          }).catch(error => {
            console.error(error);
            controller.error(error)                  
          })
        }
      }
    })
  );
})
.then(response => response.blob())
.then(data => {
  console.log('download completed');
  // document.getElementById('img').src = URL.createObjectURL(data);
})
.catch(error => {
  console.error(error);
});

If that code confuses you, it’s mostly the Fetch + ReadableStream example code from MDN. The key additions are:

  • Extract the length from the content-length header. If some encoding is used, the server must send the x-file-size header instead
  • Store total bytes and loaded
  • Increment loaded and calculate the progress (here: logged to the console)
  • Do something with the data (here: commented out)

Can also be used from within a ServiceWorker.

Fetch & Streams API Progress Indicator Source Code (GitHub) →
Fetch & Streams API Progress Indicator Demos →

ORBX.js – A Downloadable HD Codec Written in JS and WebGL

ORBX.js is a JavaScript library that enables Windows, Linux or Mac OSX apps to be virtualized in the cloud and streamed to any HTML5-enabled browser, including those running on mobile devices

Really impressive stuff. In the video above Steam is being run somewhere in the cloud and streamed to the client which is Firefox. Rendering via ORBX.js and WebGL. Specs are impressive too:

25% better compression than H.264 for competitive quality, adaptive bit-rate while streaming, integer and (soon) floating point coding, better color depth, better intra-frame coding, a more parallelizable design — the list goes on.

Reminds me of a few existing ActiveX plugins for IE, such as the one by VMWare to accessing your remote machines from within the browser.

Today I Saw The Future →

(via De Wasstraat #28)