Search code examples
javascriptphppromisecallstackorder-of-execution

Problem with Execution order i would guess


im loosing my mind! I try to get data from a form and pass it to a php script that puts the data in a csv file and into a database. This Works, however i am trying to validate the Transmission of the data with Javascript and the response i get from the php script. When the php script added the files correctly to the db it adds a key:value pair to the transmitted data which i wanna check and determine if the data was put into the db. however when i execute the script my object value that i add after the resposne i get from the php script to check if the are the same Always will be populated right at the beginning.

PHP side:

$Submitted_data = json_decode(file_get_contents('php://input'), true); //saving the Post Request

//process data

if ($conn->query($sql) === TRUE) {
    $Submitted_data["sqlTX"] = "New record created successfully";
    echo json_encode($Submitted_data);
} else {
  echo "Error: " . $sql . "<br>" . $conn->error;
}

On Success i add the Key "sqlTX" with Value "New record created successfully" since i dont call the .php file from the form directly, i call it with javascript fetch to prevent loading the php site and users stay on the site they are. so i try to validate the data put into the db by comparing the transmitted object where i added the key:value with the object formattedFormData that i used to send to the phph script. Since i now what key:value i will expect to get i add this to the object that i used to pass into the script after i used fetch to transmit the data, however when i log the object to console it is always on the first time i check it populated with the

function txData() {

  const form = document.getElementById('dataInput');
  const time = new Date().toLocaleDateString('en-EN') + " - " + new Date().toLocaleTimeString('en-EN');
  const formattedFormData = {} //resetting object since i was thinking thats the issue

     
  formattedFormData.Name = form.Name.value;
  formattedFormData.Attend = form.Attend.value;
  formattedFormData.Participants = form.Participants.value;
  formattedFormData.Contact = form.Contact.value;
  formattedFormData.Message = form.Message.value;
  formattedFormData.Timestamp = time;
    
    console.log("initial formattedFormData");
    console.log(formattedFormData);

  return fetch('submitAttendance.php',
    {
        method: 'POST',
        body: JSON.stringify(formattedFormData)
        
    })
    .then(function(response) {
      return response.json();
    })
    .then(function(data) {
      console.log("data");
      console.log(data);

      console.log("before adding key:value");
      console.log(formattedFormData);

      formattedFormData.sqlTX = "New record created successfully!!!!!!"; //Adding !!!!! to be able to see the difference in the console log and get a return false for further error handling

      console.log("after adding key:value");
      console.log(formattedFormData);
      
      if(data == formattedFormData){
        console.log("postdata true");
        return true;
      }
      else {
        console.log("postdata false");
        return false;
      }

    })
}

Why is formattedFormData on the first console.log("initial formattedFormData"), right after initializing populated with the key:value "sqlTX":"New record created successfully!!!!!!" even i used then() to wait for the fetch to finish? That way the script would allays indicating successful run even when the transmission or database input failed? Im sure there is something i dont understand or get wrong from the concept...

Was having this in a normal function, changed it to async/await and now Promise with then() since i was thinking the issue has to do with execution order. Readed about the call stack and trying lots of debugging to find out why the variable is getting the key:value right after initializing it but cant get an answer


Solution

  • My assumption is that your problem is that you are simply looking at the object after the property was already added.

    The devtools use lazy expansion, so only at the moment of time you click the ▶ arrow, it will load all the properties from the object to display. (If it wasn't like that, imagine what would happen if you would log window... your RAM usage would jump up 100MB every time if it had to copy the whole environment.)

    Try logging JSON.stringify(formattedFormData) or formattedFormData.sqlTX directly so that field gets loaded and logged right at that moment and not later when you click the arrow. You can also use the debugger to set a breakpoint directly after the console.log so that you can click the arrow before the rest of the code ran.


    To understand what I mean try this:

    const x = { a: 1 }
    console.log(x)
    x.a = 2
    console.log(x)
    

    You will see { a: 1 } and { a: 2 } initially because that single-line preview is evaluated right away, but if you then click the arrow next to { a: 1 } you will see the object expanding with a: 2 because that's the value it has at the moment you clicked the arrow!

    example

    But if you were to put a breakpoint at x.a = 2 and then expand the object at that moment (before the line x.a = 2 gets executed), you would see a: 1:

    example 2

    The i tooltip actually warns you about this in a way (but it says it backwards, stating that the value may have changed since then, but in fact it could also have changed before that):

    tooltip