20

Note: I'm not looking for any alternatives. I know this can be done with XMLHttpRequest. I also don't care about browser support. I just want learn about the new/upcoming standards.

I have a File object and I can upload it with PUT using fetch like this:

fetch(url, {
    method: "PUT",
    body: fileObject,
});

How can I get upload progress from this?

From what I understand the body of the fetch options can be a ReadableStream. So maybe there is a way to wrap the File object to a ReadableStream and get progress status from that?

Eg. something like this

fetch(url, {
    method: "PUT",
    body: asReadableStream(fileObject, onProgress),
});

Thanks.

Zachary Craig
  • 2,192
  • 4
  • 23
  • 34
esamatti
  • 18,293
  • 11
  • 75
  • 82
  • 1
    Possible duplicate of [Fetch with ReadableStream as Request Body](https://stackoverflow.com/questions/40939857/fetch-with-readablestream-as-request-body) – anthumchris Nov 06 '18 at 17:39
  • 1
    Does this answer your question? [Upload progress indicators for fetch?](https://stackoverflow.com/questions/35711724/upload-progress-indicators-for-fetch) – 17xande Feb 10 '22 at 07:51

2 Answers2

12

Update

Chrome started to support streaming uploads https://chromestatus.com/features/5274139738767360

Here is a demo using a pull stream that the request calls when it's ready to accept more data for uploading

let uploaded = 0
let buf = new Uint8Array(1024 * 50)
let start = Date.now()

var rs = new ReadableStream({
  pull(ctrl) {
    uploaded += buf.byteLength
    console.log('uploaded', uploaded)
    crypto.getRandomValues(buf)
    ctrl.enqueue(buf)
    if ((start + 1000) < Date.now()) ctrl.close()
  }
})

fetch('https://httpbin.org/post', {
  method: 'POST',
  body: rs,
  duplex: 'half'
}).then(r => r.json()).then(console.log)

As Kyle said, ReadableStream uploading is not supported yet. https://github.com/whatwg/fetch/issues/95

Even if it is possible I would not try to monitor the upload progress throught streams, (that is if FetchObserver becomes a thing) Nobody is working on it right now. But Mozilla made a proposal that looks something like this.

/*
enum FetchState {
  // Pending states
  "requesting", "responding",

  // Final states
  "aborted", "errored", "complete"
};
*/

fetch(url, {
  observe(observer) { 
    observer.onresponseprogress = e => console.log(e);
    observer.onrequestprogress = e => console.log(e);
    observer.onstatechange = n => console.log(observer.state)
  }
)

I remember that i tested it using some experimental flags a long time ago but can't find the demo anymore, guess they removed it from MDN since it was there own implementation/suggestion.

enqueue bytes to a readable or a identity stream don't mean that you have uploaded the data to the server, it only signals that the request asking for more data to potentially fill up a bucket

Endless
  • 34,080
  • 13
  • 108
  • 131
2

Short answer: cannot be done right now.

Checkout the spec here: https://fetch.spec.whatwg.org/#fetch-api

Second sentence indicates that there isn't a way to track request progression when using fetch.

The fetch() method is relatively low-level API for fetching resources. It covers slightly more ground than XMLHttpRequest, although it is currently lacking when it comes to request progression (not response progression).

Kyle
  • 2,946
  • 1
  • 13
  • 11