JavaScript/JQuery循环对象时availableAt属性值异常问题
TSP路由算法中遍历trucks时availableAt值被统一覆盖的问题解决
问题描述
我们正在开发旅行商问题(TSP)路由算法,流程如下:
- 异步函数
acquireData通过$.getJSON调用自研API,获取包含货车、行程的原始数据 - 遍历原始数据构建精简后的
newData对象:为有行程的车辆调用谷歌地图API计算availableAt时间,无行程的车辆默认设置为当前时间加24小时的值 - 在
acquireData().then()中直接打印data对象时,data.trucks的availableAt值符合预期;但使用$.each遍历data.trucks时,所有车辆的availableAt都变成了同一默认时间,与初始打印结果不符
问题根源
核心问题是异步操作的执行顺序错误:
- 处理有行程的车辆时,
callGoogle是异步请求,其.then回调会在后续事件循环中执行 - 但在
callGoogle的异步回调完成前,代码已经执行了truckObj.availableAt = tomorrow并将truckObj存入newData.trucks[j],随后直接resolve(newData) - 此时
console.log(data)打印的是异步回调执行前的对象快照,而当遍历执行时,要么异步回调还未完成,要么已被后续的默认值覆盖,导致所有availableAt显示为同一时间
解决方案
需要确保所有异步操作完成后再返回newData,将每个车辆的处理包装为Promise,等待全部完成后再结束acquireData函数。修改后的代码如下:
async function acquireData() { // 先获取原始数据,转为Promise简化异步流程 const rawData = await new Promise((resolve, reject) => { $.getJSON('https://xxxxxxxxxx/xxxxx.php', resolve).fail(reject); }); const newData = { trucks: {}, trips: [], trips_unscheduled: [] }; // 收集所有车辆处理的Promise,等待全部完成 const truckPromises = []; $.each(rawData.trucks, function(j, k) { if (!j.includes('Med') && j !== "") return; const truckObj = { trips: [], standing_location: k.name_value_list.location_c.value }; // 处理车辆的行程分类 if (k.trips) { for (let i = 0; i < k.trips.length; i++) { const tripDate = new Date(k.trips[i].name_value_list.transport_date_2_c.value); const now = new Date(); const timeDiff = tripDate - now; const diffInHours = timeDiff / (1000 * 3600); const tripObj = { trip_id: k.trips[i].name_value_list.trip_id_c.value, dropoff_location: formatCityState(k.trips[i].name_value_list.arrival_city_c.value, k.trips[i].name_value_list.arrival_state_c.value), pickup_location: formatCityState(k.trips[i].name_value_list.departure_city_c.value, k.trips[i].name_value_list.deprature_state_c.value), pickup_time: createDateObject(k.trips[i].name_value_list.transport_date_2_c.value, k.trips[i].name_value_list.pick_up_time_c.value, k.trips[i].name_value_list.trip_id_c.value) }; if (diffInHours > 48 && tripObj.pickup_time != "No Date") { newData.trips.push(tripObj); } else if (diffInHours < -45000 || tripObj.pickup_time == "No Date") { newData.trips_unscheduled.push(tripObj); } else { truckObj.trips.push(tripObj); } } } // 为每个车辆创建异步处理的Promise const truckPromise = (async () => { if (truckObj.trips.length > 0) { // 有行程的车辆,调用谷歌API计算availableAt const lastTrip = truckObj.trips[truckObj.trips.length - 1]; const googleData = await callGoogle(lastTrip.pickup_location, lastTrip.dropoff_location); truckObj.availableAt = addSeconds(lastTrip.pickup_time, addHalfHourEvery4Hours(googleData.rows[0].elements[0].duration.value)); } else { // 无行程的车辆设置默认时间 let t = new Date(); truckObj.availableAt = new Date(t.setHours(t.getHours() + 24)); } newData.trucks[j] = truckObj; })(); truckPromises.push(truckPromise); }); // 等待所有车辆的异步处理完成 await Promise.all(truckPromises); return newData; }
修改说明
- 将原始数据的获取转为
await Promise,简化异步流程的嵌套 - 为每个车辆的处理创建独立的Promise,包含异步的谷歌API调用
- 使用
Promise.all等待所有车辆的异步操作完成后,再返回newData,确保所有availableAt都已正确赋值 - 将无行程车辆的默认时间设置移到Promise内部,避免覆盖异步计算的结果
内容的提问来源于stack exchange,提问作者acc_it
相关产品推荐
相关产品推荐

