Home > front end >  why this code returns undefined when I first run
why this code returns undefined when I first run

Time:11-19

I want to get a base64 string from an uploaded image. First time when i run the code, it returns undefined. When i run after it works fine. How can i fix this?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Upload</title>
  </head>
  <body>
    <input type="file" id="file">
    <button id="button" onclick="upload()">Upload</button>
    <script type="text/javascript">
      var result;

      function getBase64(file) {
         var reader = new FileReader();
         reader.readAsDataURL(file);
         reader.onload = function () {
           result = reader.result;
         };
         reader.onerror = function (error) {
           console.log('Error: ', error);
         };
         return result;
      }

      function upload() {
        var file = document.querySelector('input').files[0];
        console.log(getBase64(file));
      }
    </script>
  </body>
</html>

CodePudding user response:

The answer ASDFGerte linked does explain this, but I will explain in the context of your question.

Lets examine what happens:

user clicks button

function upload executes

getBase64 is called

create a file reader and read file

assign a function to the .onload event listener

assign a function to the .onerror event listener

return variable result, which at this point does not exist, because .onload event has not been triggered yet.

After your second click, the event has triggered, but for the previous result, not a new result.

The second goal is to fix this, and my favorite way is using the async await syntax.

check out this rework of your code

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Upload</title>
  </head>
  <body>
    <input type="file" id="file">
    <button id="button" onclick="upload()">Upload</button>
    <script type="text/javascript">
      async function getBase64(file) {
         var reader = new FileReader();
         reader.readAsDataURL(file);
         let result;
         await new Promise(resolve => {
           reader.onload = function () {
             result = reader.result;
             resolve();
           };
           reader.onerror = function (error) {
             console.log('Error: ', error);
             resolve();
           };
         });
         return result;
      }

      async function upload() {
        var file = document.querySelector('input').files[0];
        const result = await getBase64(file);
        console.log(result);
      }
    </script>
  </body>
</html>

CodePudding user response:

function getBase64(file) {
   var reader = new FileReader();
   reader.readAsDataURL(file);
   reader.onload = function () {
     return reader.result;
   };
   reader.onerror = function (error) {
     console.log('Error: ', error);
   };
}

async function upload() {
  var file = document.querySelector('input').files[0];
  let result = await getBase64(file)
  console.log(result);
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

FileReader runs asynchronously so reader.onload does not complete instantly. You return result before reader.onload has finished so result does not have a value.

The second time you run upload, result does have a value because reader.onload has finished. The result logged will most likely be the result from the previous call to upload.

You can fix this by making upload an asynchronous function that uteawaits a response from getBase64. This will also require you rn the result in reader.onload instead of setting the value globally in the <script> tag

CodePudding user response:

you need to declare FileReader outside of upload() and use the onload function for the console.log.

var reader = new FileReader();
      
reader.onload = function (event) {
 var dataURL = event.target.result;
 console.log(dataURL);
};

in update function use only readDataURL

function upload() {
 var file = document.querySelector("input").files[0];
 reader.readAsDataURL(file)
}
  • Related