Javascript – Download file stream as it’s being generated

javascriptstream-processinguser interfaceweb-development

Scenario

We are building a UI that allows users to query our data in bulk. The return format is CSV and there is a decent amount of processing that needs to happen, so this processing processing is done in parallel and then sets of rows are streamed back to the UI.

Current Implementation

An AJAX POST request is sent to the server, it waits for all of the data to come in and then uses createObjectURL to trigger a download. The issue is that it can take several minutes for the request to complete and the user sees a spinning indicator indicating that their request is in progress.

Problem

It's a bad experience that the user cannot see any other progress and has no idea whether their request is actually processing or how long it will take.

Goal

To have the browser download the file as it's being streamed back to the client.

Obstacle

It does not seem possible to enable this behavior in JavaScript. The closest that I found was a script StreamSaver.js but using an external MITM is not acceptable and I don't understand the code well enough to determine whether this is a viable (or even good approach).

Other Ideas

  • Use a GET request or a form. The issue here is two-fold: (1) The request data can be nested and of variable length. It doesn't seem right to have to be parsing a request string on the backend. (2) It seems like this causes a page reload, which kills the state of the React application.

  • Instead of downloading the file continuously on the client, we can add a progress bar instead. To be this, we could add a header to the response indicating how many chunks are expected and then increment when each chunk is received. The downside of this approach is that the user cannot cancel the request and they cannot recover partial results.

Help

It feels like I'm missing a much better solution to this issue. Please feel free to challenge any of the assumptions above. My main goal is to get a clean solution that provides a good user experience.

Notes

The backend is a C# web application, React is being used on the front-end, and it's possible to pipe through a PHP layer if somehow that would help.

Best Answer

I think what you are looking for is ReadableStream

https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream/getReader

you can generate one from a fetch request and stream it as required

https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams

Related Topic