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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:27:19