deepsky deepsky - 10 months ago 73
Ajax Question

How to get XMLHttpRequest Promise progress

I am using JS Promise to refactor our JS API. However I met a problem which stops me from going further.

Basically, one of our API is to issue a async GET request and download a large file.

So the usage of the API would like this:

var callback = {
success: function(data){...},
failure: function(data){...}

Test(token).download(url).then(callback.success, callback.failure);

The Test function makes a XHR request to the url and calls the callback functions in onload & onerror event handlers.

The problem is during the download procedure, the UI needs to be refresh, i.e. the progress bar, which is handled in onprogress.

The callback.success will only be called once when the Promise is resolved. So how should I implement the UI refresh callback which should be called in onprogress event handler of the inner XHR component of Test function?

Answer Source

Promises are simply not a good architectural match for multiple progress notifications. Promises are a one-way state machine meant to communicate completion or error - that's really all they are designed for. They do not have any mechanism built-in for doing multiple progress notifications.

Instead, for progress notifications, you should some other architectural mechanism such as a regular callback that is called each time or an eventEmitter that triggers multiple progress events.

In the scheme you've shown so far, it would probably look like this:

var callback = {
  success: function(data){...},
  failure: function(data){...},
  progress: function(data){...}

Test(token).download(url, callback.progress).then(callback.success, callback.failure);

Then, inside your download() function, you call the progress callback as many times as appropriate.

Personally, I think it would be more useful to your callers if you just returned the promise and let them supply resolve and reject handlers themselves rather than hiding the promise and making your callers live with the year 2013 callback architecture. Returning the promise allows them to use all the promise features such as chaining, aggregation with other promises, error propagation in their own code, etc...

So rather than passing in a callback object with multiple callbacks, all they pass in is the progress callback and you return back a promise. The caller can then attach their own resolve and reject handlers on the returned promise. It's 2016 and promises are standardized in ES6. There's no need to hide them from your callers and there's every reason to return the promise so your callers can tap into the benefits of promises too.