Read a file synchronously in Javascript

Laila picture Laila · Jun 12, 2013 · Viewed 52.1k times · Source

I would like to read a file and convert it into a base64 encoded string using the FileReader object. Here's the code I use :


    var reader = new FileReader();
    reader.onloadend = function(evt) {  
        // file is loaded
        result_base64 = evt.target.result; 
    };
    reader.readAsDataURL(file); 


But in this case, I get the result of the conversion in the event handler (onLoadEnd event). I would like a synchronous method. Is there a way the "readAsDataURL" method can return directly the value of the 'result_base64' variable ?

Answer

John Weisz picture John Weisz · Mar 14, 2019

You can use the standard FileReaderSync, which is a simpler, synchronous, blocking version of the FileReader API, similar to what you are already using:

let reader = new FileReaderSync();
let result_base64 = reader.readAsDataURL(file); 

console.log(result_base64); // aGV5IHRoZXJl...

Keep in mind though that this is only available in worker threads, for obvious reasons.


If you need a solution for the main thread that "reads like" a synchronous API, i.e. sequentially, you can wrap the async FileReader in a promise and use async functions (you might need to transpile):

async function readFileAsDataURL(file) {
    let result_base64 = await new Promise((resolve) => {
        let fileReader = new FileReader();
        fileReader.onload = (e) => resolve(fileReader.result);
        fileReader.readAsDataURL(file);
    });

    console.log(result_base64); // aGV5IHRoZXJl...

    return result_base64;
}

And then you can either await this function in another async context:

async function main() {
    let file = new File(...)
    let dataURL = await readFileAsDataURL(file)
    console.log(dataURL); // aGV5IHRoZXJl...
}

... or just consume it using promise callbacks (doesn't need an async context):

readFileAsDataURL(file).then(dataURL => {
    console.log(dataURL); // aGV5IHRoZXJl...
});