21

I'm trying to read a file using FileReader:

async readFile(event: any) {
    var file = event.target.files[0];
    var data:string
    if (file) {   
        var reader:FileReader = new FileReader();
         reader.onload = async function (evt : FileReaderEvent) {
            data = await evt.target.result;
            console.log(evt.target.result);

        };
        console.log(file);
        console.log(data);
        await reader.readAsText(file);
        await this.processFileContent(data);
    }
 }

However, evt.target.result still gets printed after my console.log(file) call.

Does anyone know how I can obtain the result of the file and pass it to my processFileContent function?

blazerix
  • 770
  • 4
  • 8
  • 24
  • does `processFileContent` expect a `File` object (which is what you're giving it now) or a `string` ? – Touffy Jan 09 '18 at 16:54
  • @Touffy it expects a string – blazerix Jan 09 '18 at 16:56
  • Then that's your first problem. You're reading the file, but then you're not saving the result anywhere, much less passing it to `this.processFileContent`. – Touffy Jan 09 '18 at 16:57
  • i guess it's printed first because it's before the await. and the async inner function will be called later inside the event loop... – snap Jan 09 '18 at 16:58
  • @Touffy I updated the code so that I store the result, but still having issues – blazerix Jan 09 '18 at 17:00
  • Yes, it's getting better in your edit. Now you're passing it a `Promise`. What you seem to be missing is that `await` *returns a value*. It's not just a void instruction to wait for the Promise to resolve, it also extracts the Promise's value. So: `data = await evt.target.result` – Touffy Jan 09 '18 at 17:02
  • (seriously, what's the point of TypeScript if you're not going to type your functions to detect these issues statically?) – Touffy Jan 09 '18 at 17:05
  • @Touffy Thank you for the reply! I'm new to both typescript and asynchronous javascript, so it is a little bit confusing for me. I've updated the code to reflect my latest changes. The code in reader.onload still seems to be getting executed after everything else and data is undefined when I'm passing it into processFileContent – blazerix Jan 09 '18 at 18:38

3 Answers3

34

Use the new read methods on the blob itself

/** @type {Event} evt */
async readFile (evt) {
  const [file] = evt.target.files
  if (!file) return
  const data = await file.text()
  return this.processFileContent(data)
}

Alternative:

evt.target.files[0]?.text().then(this.processFileContent)
Endless
  • 34,080
  • 13
  • 108
  • 131
14

Needed to leverage reader to convert blob to base64, prefer to use async-await syntax so I chose to extract reader logic into helper like this:

//* Convert resBlob to base64
export const blobToData = (blob: Blob) => {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onloadend = () => resolve(reader.result)
    reader.readAsDataURL(blob)
  })
}

and calling it using await in main code:

//* Convert resBlob to dataUrl and resolve
const resData = await blobToData(resBlob)
Be Kind
  • 4,712
  • 1
  • 38
  • 45
  • 1
    @MartinsOnuoha there's no error handling though. If you do implement it, feel free to update the answer. – Be Kind Aug 27 '21 at 05:14
-1

const logFile = async (e) => {
  const { image } = await readImage(e.target.files[0])
  document.getElementById("image").appendChild(image)
}

const readImage = (
  file
) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = (e) => {
      const image = new Image();
      image.src = e.target?.result;

      image.onload = () => {
        resolve({ image, sizeInMB: Math.round(file.size / 1024 / 1024) });
      };

      image.onerror = () => {
        reject(`couldn't read image`);
      };
    };

    reader.onerror = (e) => {
      reject(`couldn't read image`);
    };

    reader.readAsDataURL(file);
  });
};
#image > img {
  width: 100px;
  height: 100px;
}
<strong>upload image</string>
<input type="file" onchange="logFile(event)" />
<div style="width:100px;height:100px" id="image"></div>
rohit
  • 19
  • 1
  • why post something about using images when OP tries to read files as text? also it's better to just simply just use URL.createObjectURL instead of using the fileReader. and if you want to await image load then use [image.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) – Endless Apr 13 '23 at 22:47