Update: Find the complete solution at the end of this answer.
Consider the following code snippet:
@Injectable()
export class FileUploader {
constructor(private http: Http) {}
upload(url: string, file: File) {
let fileReader: FileReader = new FileReader();
return new Promise((resolve, reject) => {
fileReader.onloadend = (e) => {
// you can perform an action with read data here
let content = fileReader.result;
console.log('starting upload');
return this.http.post(url, content)
.map((res) => res.json()).toPromise();
};
fileReader.readAsArrayBuffer(file);
});
}
and usage like
this.fileuploader.upload('/backend/upload', content).then(); // do something
However, if a user selects multiple files (like creating an album on Facebook), all files will be uploaded simultaneously, causing the browser to become completely unresponsive.
My idea was to store an array of promises in a property and have another private method trigger the first one. Once it is done, the promise would call that method again to start a new upload until all are completed.
I've tried various combinations without success, and I couldn't even get them to compile. The code above isn't mine; I found it in response to a different question.
How can I accomplish this task?
Edit: Following the advice from @toskv, I have implemented the solution below. I've updated my answer to help others facing the same issue.
Thank you once again to @toskv for the assistance.
@Injectable()
export class FileUploader {
private currentTask: Promise<any> = null;
constructor(private http: Http) {}
upload(url: string, file: File) {
let action = () => {
return new Promise((resolve) => {
let fileReader: FileReader = new FileReader();
fileReader.onloadend = (e) => {
let content = fileReader.result;
return this.http.post(url, content)
.map((res) => res.json()).toPromise()
.then((json) => {
resolve(json);
});
};
fileReader.readAsArrayBuffer(file);
})
};
return this.doNext(action)
}
private doNext(action: () => Promise<any>): Promise<any> {
if (this.currentTask) {
// if something is in progress do it after it is done
this.currentTask = this.currentTask.then(action);
} else {
// if this is the only action do it now
this.currentTask = action();
}
return this.currentTask;
}
}