Cancellable?
sircommitsalot opened this issue · 1 comments
Hey @timdp, great project! I'm currently using it to concurrently upload chunks of large video files directly to Azure blob storage. I've gained a ton of throughput and my code is much cleaner.
I have a use case that involves cancellation. Much like Google Drive's uploader, I want each file added to my uploader to be cancellable. When Uploader.cancel() is called, we flip this.cancelled to prevent new Promises from being produced; this halts the pool.
However, at that point, the pool still has as many as 4 pending promises, each uploading a chunk of data in an ajax request. Ideally, I'd like to ask the pool to call the .abort method on each ajax request's returned XHR object to kill the network transfers.
Do you have any recommendation on how to do this? Right now, I store each returned XHR object in a member Array (this.xhrs), and when Uploader.cancel() is called, I iterate through this.xhrs and call abort on each. It's a little sloppy.
Here's the gist:
import PromisePool from 'es6-promise-pool';
class Uploader {
constructor (file) {
this.file = file;
this.bytesRemaining = file.size;
this.cancelled = false;
this.pool = {};
}
upload () {
this.pool = PromisePool(this.chunkUploadProducer, 4)
.start()
.then(() => {}, (error) => { throw error })
}
cancel () {
// This will prevent new promises from being produced
this.cancelled = true;
// But how do we call into the pool
// and tell it to abort the current ajax requests?
}
chunkUploadProducer () {
if (this.bytesRemaing > 0 && !this.cancelled) {
return this.uploadChunk().catch(error => { throw error });
}
return null;
}
uploadChunk () {
return this.readChunkFromFile()
.then((chunk) => {
// the XHR object returned from the $.ajax call
// has a .abort() method that we can call to terminate
// data transfer
return $.ajax({
url: 'www.azure.com/blob/{containerId}',
data: chunk
// other config
})
});
}
readChunkFromFile () { // do some file processing }Eager to hear your insight. Thanks again!
Currently, ES6 Promise Pool doesn't have any support for cancelation. It might be relatively easy to add though. I'd have to think about it.
At any rate, you'd first need to select a cancelation implementation. There's a proposal for native support but Bluebird has supported it for a long time. Unfortunately, the APIs are entirely incompatible (and the previous major version of Bluebird was actually totally different as well). If you search npm, you'll probably find other ways, but it seems to me like Bluebird is the obvious choice at this point, at least until native support comes through, and then they'll probably change Bluebird again.
Tangentially related: a while ago, I also needed promise cancelation at my job. However, the problem was more broad: I was looking for a way to orchestrate tasks (i.e., wire them up for sequential and parallel execution) and track their progress. It's a common problem (Gulp, for example, tries to solve it as well) but I couldn't find anything that allowed me to model the tasks the way I wanted. At best, it would have been an awkward mix of a few modules. In the end, I built something on top of Bluebird that I called Chiffchaff. It's nowhere near as mature as for example Bluebird but we're successfully using it in production. Depending on your use case, you might want to take a look at it.