You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript Fetch执行顺序异常:formattedFormData提前赋值问题

问题描述

我使用JavaScript的Fetch API将表单数据提交至PHP脚本,该脚本负责将数据写入CSV文件与数据库,这一流程本身可以正常运行。我希望通过PHP返回的响应校验数据是否成功写入数据库:PHP在成功写入时会给返回的JSON添加sqlTX键值对,我则在Fetch的then回调中给提交用的formattedFormData对象添加对应键值对,再与PHP返回的数据进行对比。但我发现,即使使用then保证异步执行顺序,初始化formattedFormData后立即打印的日志中已经存在后续添加的sqlTX键值对,导致校验逻辑失效。我尝试过普通函数、async/await及Promise then写法,仍未解决该问题,想了解这一异常的原因。

PHP代码
$Submitted_data = json_decode(file_get_contents('php://input'), true); // 保存POST请求数据

// 数据处理流程

if ($conn->query($sql) === TRUE) {
    $Submitted_data["sqlTX"] = "New record created successfully";
    echo json_encode($Submitted_data);
} else {
  echo "Error: " . $sql . "<br>" . $conn->error;
}
JavaScript代码
function txData() {
  const form = document.getElementById('dataInput');
  const time = new Date().toLocaleDateString('en-EN') + " - " + new Date().toLocaleTimeString('en-EN');
  const formattedFormData = {} // 重置对象,曾以为是这里的问题

  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!!!!!!"; // 加感叹号方便在控制台区分,用于后续错误处理的返回false测试

    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;
    }
  })
}
原因分析与解决方法

异常原因

  1. 浏览器控制台的引用式展示特性:你打印formattedFormData时,控制台并不会立即生成对象的快照,而是保存了对象的引用。当后续代码给对象添加了sqlTX键后,你在控制台展开这个对象,浏览器会读取它的当前状态,导致看起来初始化时就已经有这个键。
  2. 对象引用对比而非内容对比:JavaScript中用==或===直接比较两个对象,对比的是它们的内存引用,而不是内容。哪怕两个对象的键值对完全一致,只要不是同一个对象实例,结果都是false,这直接导致你的校验逻辑失效。
  3. 键值内容不匹配:你给formattedFormData添加的sqlTX值是带感叹号的,和PHP返回的原始值不一致,就算前面的问题解决,对比也会失败。

解决方法

  1. 打印对象快照:打印时用JSON.stringify()将对象转为字符串,这样就能看到打印时刻的真实状态:
    console.log("initial formattedFormData", JSON.stringify(formattedFormData));
    
  2. 正确对比对象内容:不要直接比较引用,改用以下两种方式:
    • 序列化字符串对比:将两个对象转为JSON字符串后对比(注意对象键的顺序会影响结果)
      if(JSON.stringify(data) === JSON.stringify(formattedFormData)) {
        console.log("postdata true");
        return true;
      } else {
        console.log("postdata false");
        return false;
      }
      
    • 逐个键值校验:遍历对象的所有键,逐一对比值,这种方式更可靠:
      function isEqual(obj1, obj2) {
        const keys1 = Object.keys(obj1);
        const keys2 = Object.keys(obj2);
        if(keys1.length !== keys2.length) return false;
        for(const key of keys1) {
          if(obj1[key] !== obj2[key]) return false;
        }
        return true;
      }
      
      // 在校验逻辑中使用
      if(isEqual(data, formattedFormData)) {
        console.log("postdata true");
        return true;
      } else {
        console.log("postdata false");
        return false;
      }
      
  3. 统一键值内容:将formattedFormData.sqlTX的值改为和PHP返回的一致,即"New record created successfully"。

内容的提问来源于stack exchange,提问作者360Bits

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:55:04