Fetch: upload progress?

Created on 19 Feb 2015  路  12Comments  路  Source: github/fetch

Is there any way I can attach a progress listener to the xhr.upload object used in fetch?

xhr.upload.addEventListener('progress', function(){ ... })

since I use fetch to upload files, I would find this very useful.

Most helpful comment

I guess you could just go with

function futch(url, opts={}, onProgress) {
    return new Promise( (res, rej)=>{
        var xhr = new XMLHttpRequest();
        xhr.open(opts.method || 'get', url);
        for (var k in opts.headers||{})
            xhr.setRequestHeader(k, opts.headers[k]);
        xhr.onload = e => res(e.target.responseText);
        xhr.onerror = rej;
        if (xhr.upload && onProgress)
            xhr.upload.onprogress = onProgress; // event.loaded / event.total * 100 ; //event.lengthComputable
        xhr.send(opts.body);
    });
}

futch('/').then(console.log)

for now

All 12 comments

The XHR instance is an implementation detail of the polyfill that is not exposed to callers.

The best way to upload files, with progress events, is still using XHR directly rather than fetch. You might open an issue on the Fetch API repository to request this feature, though!

Thanks. I just filed an issue there.

Progress is something that is important to me. As such also willing to implement a best-attempt polyfill today for progress likely by implementing the needed subset of a readable stream.

From reading responses to the previous issue and asking some questions is seems like: response.body will be a readable stream from https://streams.spec.whatwg.org/ and you'll also be able to provide a readable stream when creating responses too. Streams everywhere

I suspect the response.body byte stream may carry sufficient information to create reasonable progress events. That being said, from my quick reading this will likely be more be more verbose then I suspect most would want to endure. (but maybe its ok?)

// example source https://github.com/yutakahirano/fetch-with-streams/

function consume(stream, total = 0) {
  while (stream.state === "readable") {
    var data = stream.read()
    total += data.byteLength;
    console.log("received " + data.byteLength + " bytes (" + total + " bytes in total).")
  }
  if (stream.state === "waiting") {
    stream.ready.then(() => consume(stream, total))
  }
  return stream.closed
}
fetch("/music/pk/altes-kamuffel.flac")
  .then(res => consume(res.body))
  .then(() => console.log("consumed the entire body without keeping the whole thing in memory!"))
  .catch((e) => console.error("something went wrong", e))

Maybe @Domenic or @jakearchibald have some ideas how this can be improved? Or how one may want to interact with it in such a way that this is easier to digest. Or how the polyfil may look.

I suspect we should assemble some examples where progress is used (data-binding/etc). This will help us craft something that is hopefully ergonomically appealing.

Is there a current work-around if we need to track progress of a file-upload with the fetch polyfill? Or are we forced to use a different library or XHR directly?

@axelson Since fetch itself doesn't support progress callbacks, you're forced to use XHR directly, unfortunately. There's nothing to stop you from using 3rd-party libraries for this either, but this polyfill can't help with your need.

@mislav in the meantime, would it be possible to expose the xhr object fetch uses to make this easier? I built a REST client using fetch and need to display upload progress on just one POST. It would suck having to rewrite the whole thing just for this one case.

To others, for posterity: @olalonde's question got answered in a separate thread: https://github.com/github/fetch/pull/290#issuecomment-193988256

I guess you could just go with

function futch(url, opts={}, onProgress) {
    return new Promise( (res, rej)=>{
        var xhr = new XMLHttpRequest();
        xhr.open(opts.method || 'get', url);
        for (var k in opts.headers||{})
            xhr.setRequestHeader(k, opts.headers[k]);
        xhr.onload = e => res(e.target.responseText);
        xhr.onerror = rej;
        if (xhr.upload && onProgress)
            xhr.upload.onprogress = onProgress; // event.loaded / event.total * 100 ; //event.lengthComputable
        xhr.send(opts.body);
    });
}

futch('/').then(console.log)

for now

When will it be supported in the fetch?

@dharmax whatwg/fetch is more where it should be discussed I think https://github.com/whatwg/fetch/issues/21

wanted native fetch methods to get the progress

This is not a place to request features for fetch. Instead, please head to https://github.com/whatwg/fetch/issues/607

Thank you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

DimitryDushkin picture DimitryDushkin  路  4Comments

karladler picture karladler  路  4Comments

hannesvdvreken picture hannesvdvreken  路  4Comments

xgqfrms-GitHub picture xgqfrms-GitHub  路  4Comments

shirotech picture shirotech  路  3Comments