服务器端点中使用await时出现变量值异常问题
问题分析与解决方案
嘿,我发现你的问题根本不是await的锅,而是浅拷贝在背后搞鬼!让我给你拆解清楚:
问题根源:浅拷贝导致嵌套对象引用共享
先看你的getOrderTemplate函数里这行代码:
const order = { ...order_template };
展开运算符...只能做浅拷贝——也就是说,它只会复制order_template的第一层属性。如果order_template是一个嵌套对象(比如里面包含recipient这个子对象),那么order.recipient其实和order_template.recipient指向的是同一个内存地址。
当你并发发送两个请求时,事件循环的执行顺序是这样的:
- 第一个请求进入
/order接口,调用getOrderTemplate,把order.recipient.name改成name1,然后执行await takeTime()——这时候当前函数会暂停,事件循环去处理第二个请求。 - 第二个请求进来,同样调用
getOrderTemplate,因为order.recipient是共享的引用,修改name为name2时,直接把第一个请求里的order.recipient.name也改成了name2! - 等第一个请求的
await结束后,再打印order.recipient.name,自然就变成了name2,这就是为什么你看到某个name只出现一次的原因。
解决方案:改用深拷贝
要解决这个问题,你需要对order_template做深拷贝,让每个请求都拿到完全独立的对象副本,不会互相干扰。这里有两种常用方法:
方法1:JSON序列化/反序列化(适合无特殊类型的对象)
如果order_template里没有函数、Date、Symbol这类无法被JSON序列化的类型,这种方法最简单:
function getOrderTemplate(shipping_info) { // 用JSON序列化实现深拷贝 const order = JSON.parse(JSON.stringify(order_template)); order.recipient.name = shipping_info.first_name order.recipient.address1 = shipping_info.address1 order.recipient.city = shipping_info.city order.recipient.state_code = shipping_info.province_code order.recipient.country_code = shipping_info.country_code order.recipient.zip = shipping_info.zip order.items = [] order.packing_slip.email = "" order.packing_slip.phone = "" order.packing_slip.message = "Welcome!" order.packing_slip.logo_url = "" return order }
方法2:递归深拷贝函数(支持特殊类型)
如果order_template里有JSON无法处理的类型,可以自己写一个递归深拷贝函数:
// 递归深拷贝工具函数 function deepClone(obj) { // 非对象类型直接返回 if (obj === null || typeof obj !== 'object') return obj; // 处理Date对象 if (obj instanceof Date) return new Date(obj.getTime()); // 处理数组 if (obj instanceof Array) return obj.map(item => deepClone(item)); // 处理普通对象 const clonedObj = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } function getOrderTemplate(shipping_info) { const order = deepClone(order_template); // 后面的代码保持不变... order.recipient.name = shipping_info.first_name order.recipient.address1 = shipping_info.address1 order.recipient.city = shipping_info.city order.recipient.state_code = shipping_info.province_code order.recipient.country_code = shipping_info.country_code order.recipient.zip = shipping_info.zip order.items = [] order.packing_slip.email = "" order.packing_slip.phone = "" order.packing_slip.message = "Welcome!" order.packing_slip.logo_url = "" return order }
验证效果
修改后,每个请求都会生成完全独立的order对象,修改recipient.name不会影响其他请求的对象。当两个请求并发执行时,你就能看到预期的输出——两个name1和两个name2(顺序可能因事件循环调度略有不同)。
内容的提问来源于stack exchange,提问作者Matteo Barberis
相关产品推荐
相关产品推荐

