Home > OS >  Asynchronous issue with Javascript FileReader
Asynchronous issue with Javascript FileReader

Time:08-24

I need to verify the file type after upload in my application and in addition to only checking the extension, I have also included magic bytes check. For that, I have used this article:

https://medium.com/the-everyday-developer/detect-file-mime-type-using-magic-numbers-and-javascript-16bc513d4e1e

Following is my method code:

checkFileTypeViaMagicByte(file):boolean {

  const filereader = new FileReader();
  const blob = file.slice(0, 4);
  filereader.readAsArrayBuffer(blob);


  filereader.onloadend= (evt) => {
    if (evt.target.readyState === FileReader.DONE) {
    // @ts-ignore
    const uint = new Uint8Array(evt.target.result);
    let bytes = []
    uint.forEach((byte) => {
      bytes.push(byte.toString(16))
    })
    const hex = bytes.join('').toUpperCase();
    console.log("SIGNATURE: "   hex);
    switch (hex) {
      case '89504E47': //image/png
        return true;
      case '25504446'://application/pdf
        console.log("PDF case");
        return true;
      case 'FFD8FFDB'://image/jpeg
      case 'FFD8FFE0':
       return true;
      default:
        return false;
    }

  };

};
 return false;
}

The issue I am having is that FileReader is async and my method always returns false. I need to perform this verification in a method because I have various methods performing checks such as filename allowed, file size etc. How can I solve this issue?

CodePudding user response:

You just need to promisify the filereader.onloadend function.

checkFileTypeViaMagicByte(file):boolean {
    const filereader = new FileReader();
    const blob = file.slice(0, 4);
    filereader.readAsArrayBuffer(blob);
    return new Promise((resolve, reject) => {
        filereader.onloadend = (evt) => {
            try {
                if (evt.target.readyState === FileReader.DONE) {
                    // @ts-ignore
                    const uint = new Uint8Array(evt.target.result);
                    let bytes = [];
                    uint.forEach((byte) => {
                        bytes.push(byte.toString(16));
                    });
                    const hex = bytes.join("").toUpperCase();
                    switch (hex) {
                        case "89504E47": //image/png
                            resolve(true);
                            break;
                        case "25504446": //application/pdf
                            resolve(true);
                            break;
                        case "FFD8FFDB": //image/jpeg
                        case "FFD8FFE0":
                            resolve(true);
                            break;
                        default:
                            resolve(false);
                    }
                }
            } catch (err) {
                reject(err);
            }
        };
    });
}

This function will return a boolean pormise you need to resolve with then

checkFileTypeViaMagicByte(file).then(res => console.log(res))

or with await/async syntax.

(async () => {
   const result = checkFileTypeViaMagicByte(file)
   console.log(result)
})()
  • Related