I am using streamsaver.js to download larger files and it works perfectly fine.
In the meantime, I want to handle cancel events from the user to stop fetching the content from the server.
Is it possible with AbortController and AbortSignal to stop readable streams fetching data?
The sample code would be below for the download part.
fetch(url, { signal: abortSignal })
.then(resp => {
for (var pair of resp.headers.entries()) {
console.log(pair[0] + ': ' + pair[1]);
}
total = Number(resp.headers.get('X-zowe-filesize'));
return resp.body;
})
.then(res => {
var progress = new TransformStream({
transform(chunk, controller) {
loaded += chunk.length;
controller.enqueue(chunk);
elem.style.width = (loaded / total) * 100 + '%';
elem.innerHTML = (loaded / total) * 100 + '%';
}
})
const readableStream = res
// more optimized
if (window.WritableStream && readableStream.pipeTo) {
return readableStream
.pipeThrough(progress)
.pipeTo(fileStream, { signal: abortSignal })
.then(() => console.log('done writing'))
}
window.writer = fileStream.getWriter()
const reader = readableStream.getReader()
const pump = () => reader.read()
.then(res => res.done
? writer.close()
: writer.write(res.value).then(pump))
pump()
})
FWIK, it is possible to use AbortController
and AbortSignal
to stop this. AbortController
allows you to create an AbortSignal
that can be passed to the fetch API as the signal option. Once the fetch API receives this signal, it will then stop fetching data from the server.
You can pass the abortSignal
to the fetch API like this: fetch(url, { signal: abortSignal })
. In the code that you provided in your post, it seems as if you have this configured correctly. You probably also may need to pass the abortSignal
to the pipeTo
method so that it can be used to stop the writing of the file to the stream if the user cancels the download.
You can pass the abortSignal
to the pipeTo
method like this: pipeTo(stream, { signal: abortSignal })
To do this, you can create a function that calls AbortController's abort()
method to cancel fetching and writing. Here is a basic implementation of how you could go about doing this:
const controller = new AbortController(); // Create a new AbortController
const abortSignal = controller.signal; // And make the signal easier to access
// Do a simple fetch and pass the signal to it
// If we don't call AbortController.abort() it will continue
fetch(url, { signal: abortSignal }).then((res) => {
// Write to a stream
if (window.WritableStream && readableStream.pipeTo) {
return readableStream
.pipeThrough(progress)
.pipeTo(fileStream, { signal: abortSignal })
.then(() => console.log("done writing"));
}
});
function cancel() {
// Call the `abort()` method and stop the fetch
controller.abort();
}
In this code, when the user calls cancel()
, the abort()
method is called on the AbortController, which then inadvertently stops the fetch()
and the readableSteam
before it is finished writing the file.