Reputation: 268
I'm using FileReader in a Vue.js project, and I have a problem with this code:
async uploadDocuments(files) {
for (let file of files) {
let fileName = file.name;
let fileContent;
let reader = new FileReader();
reader.onload = async () => {
fileContent = reader.result;
await this.submitFile(fileContent, fileName, fileType)
.then(/* THEN block */)
.catch(/* CATCH block */);
};
reader.onerror = (error) => { console.warn(error); };
reader.readAsDataURL(file);
}
console.log("COMPLETED");
}
async submitFile(fileContent, fileName, fileType) {
// this function should handle the file upload and currently contains a timeout
await new Promise((resolve) => setTimeout(resolve, 3000));
}
This is the desired execution order (example with two files):
But this is the actual execution order:
The "THEN block" is correctly executed after the timeout, but the execution of the code in the for
loop continues without waiting the execution of the onload
function.
How can I make the reader asynchronous? I tried many solutions (such as wrapping the for
loop in a promise and putting the resolve()
function inside .then()
) but none of them works.
Upvotes: 10
Views: 28208
Reputation: 8716
I'd recommend to "promisify" the Reader thing and then use Promise.all
until all the files are uploaded.
uploadDocuments = async (event, files) => {
const filePromises = files.map((file) => {
// Return a promise per file
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = async () => {
try {
const response = await this.submitFile(
reader.result,
file.name,
fileType
);
// Resolve the promise with the response value
resolve(response);
} catch (err) {
reject(err);
}
};
reader.onerror = (error) => {
reject(error);
};
reader.readAsDataURL(file);
});
});
// Wait for all promises to be resolved
const fileInfos = await Promise.all(filePromises);
console.log('COMPLETED');
// Profit
return fileInfos;
};
Upvotes: 29
Reputation: 35
Try this.
Add await before the reader.onload
it will hold until then or catch block execute successfully
async uploadDocuments(event) {
for (let file of files) {
let fileName = file.name;
let fileContent;
let reader = new FileReader();
await reader.onload = async () => {
fileContent = reader.result;
await this.submitFile(fileContent, fileName, fileType)
.then(/* THEN block */)
.catch(/* CATCH block */);
};
reader.onerror = (error) => { console.warn(error); };
reader.readAsDataURL(file);
}
console.log("COMPLETED");
}
async submitFile(fileContent, fileName, fileType) {
// this function should handle the file upload and currently contains a timeout
await new Promise((resolve) => setTimeout(resolve, 3000));
}```
Upvotes: -4