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; } }) }
原因分析与解决方法
异常原因
- 浏览器控制台的引用式展示特性:你打印
formattedFormData时,控制台并不会立即生成对象的快照,而是保存了对象的引用。当后续代码给对象添加了sqlTX键后,你在控制台展开这个对象,浏览器会读取它的当前状态,导致看起来初始化时就已经有这个键。 - 对象引用对比而非内容对比:JavaScript中用
==或===直接比较两个对象,对比的是它们的内存引用,而不是内容。哪怕两个对象的键值对完全一致,只要不是同一个对象实例,结果都是false,这直接导致你的校验逻辑失效。 - 键值内容不匹配:你给
formattedFormData添加的sqlTX值是带感叹号的,和PHP返回的原始值不一致,就算前面的问题解决,对比也会失败。
解决方法
- 打印对象快照:打印时用
JSON.stringify()将对象转为字符串,这样就能看到打印时刻的真实状态:console.log("initial formattedFormData", JSON.stringify(formattedFormData)); - 正确对比对象内容:不要直接比较引用,改用以下两种方式:
- 序列化字符串对比:将两个对象转为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; }
- 序列化字符串对比:将两个对象转为JSON字符串后对比(注意对象键的顺序会影响结果)
- 统一键值内容:将
formattedFormData.sqlTX的值改为和PHP返回的一致,即"New record created successfully"。
内容的提问来源于stack exchange,提问作者360Bits
相关产品推荐
相关产品推荐

