Google Distance Matrix API返回结果顺序错乱问题求助
解决Google Distance Matrix API结果顺序错乱&批量处理问题
看起来你遇到的核心问题是异步请求的无序性——因为Distance Matrix API的回调是异步触发的,先发送的请求不一定先返回,所以输出顺序会乱;另外批量处理5500条数据也需要考虑API配额和请求限流的问题。我来帮你一步步修复这些问题:
现有代码的关键问题
- 回调函数没有绑定对应的
id(每条数据的唯一标识),回调返回时无法对应到原始请求数据 - 异步请求没有并发控制,一次性发送大量请求容易触发API限流,也会加剧顺序错乱
- 只处理了
DRIVING一种交通方式,没实现你需要的多方式查询 - 错误处理过于简陋,没有重试机制,容易丢失数据
优化后的解决方案
我会用Promise封装API调用,结合async/await控制请求流程,同时给每个请求绑定原始数据标识,确保结果和输入一一对应:
1. 重构CSV解析逻辑
先简化CSV读取和解析,把每条数据转换成结构化对象,方便后续处理:
// 假设CSV第一行是表头,先过滤空行并跳过表头 const rows = data.split(/\r?\n|\r/).filter(row => row.trim() !== ''); const employeeData = rows.slice(1).map(row => { const cells = row.split(','); return { id: cells[0], origin: { lat: parseFloat(cells[1]), lng: parseFloat(cells[2]) }, destination: { lat: parseFloat(cells[4]), lng: parseFloat(cells[5]) } }; });
2. 用Promise封装API调用
把API请求封装成Promise,传递id和交通方式参数,方便后续关联结果:
function getTravelTime(origin, destination, travelMode, id) { return new Promise((resolve, reject) => { const service = new google.maps.DistanceMatrixService(); service.getDistanceMatrix({ origins: [origin], destinations: [destination], travelMode: travelMode, avoidHighways: false, // 可按需调整 avoidTolls: false // 可按需调整 }, (response, status) => { if (status === 'OK') { const element = response.rows[0].elements[0]; if (element.status === 'OK') { resolve({ id: id, travelMode: travelMode, duration: element.duration.text, durationValue: element.duration.value, // 数值型时长,方便后续计算 distance: element.distance.text, distanceValue: element.distance.value }); } else { reject(new Error(`查询失败:${element.status} (ID: ${id})`)); } } else { reject(new Error(`API请求失败:${status} (ID: ${id})`)); } }); }); }
3. 批量并发处理请求(控制并发数)
5500条数据不能一次性全部发送,我们控制并发数(比如同时发10个请求),最后按id排序确保结果顺序和输入一致:
// 批量处理工具函数:控制并发数,避免限流 async function processBatch(items, batchSize, handler) { const results = []; for (let i = 0; i < items.length; i += batchSize) { const batch = items.slice(i, i + batchSize); const batchResults = await Promise.all(batch.map(item => handler(item))); results.push(...batchResults); } // 按id排序,保证结果和原始输入顺序一致 return results.sort((a, b) => a.id.localeCompare(b.id)); } // 主处理函数 async function processAllData() { // 定义需要查询的交通方式 const travelModes = ['DRIVING', 'WALKING', 'BICYCLING', 'TRANSIT']; const allResults = []; for (const mode of travelModes) { console.log(`正在处理${mode}类型的请求...`); const modeResults = await processBatch(employeeData, 10, async (item) => { try { return await getTravelTime(item.origin, item.destination, mode, item.id); } catch (error) { console.error(error.message); // 错误时返回标记数据,避免中断整个流程 return { id: item.id, travelMode: mode, error: error.message }; } }); allResults.push(...modeResults); } // 渲染结果到页面表格 renderResultsTable(allResults); } // 渲染结果表格 function renderResultsTable(results) { let tableHtml = ` <table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>交通方式</th> <th>行程时间</th> <th>行程距离</th> <th>状态</th> </tr> </thead> <tbody> `; results.forEach(result => { tableHtml += ` <tr> <td>${result.id}</td> <td>${result.travelMode}</td> <td>${result.duration || 'N/A'}</td> <td>${result.distance || 'N/A'}</td> <td>${result.error ? '失败' : '成功'}</td> </tr> `; }); tableHtml += '</tbody></table>'; // 将表格插入到页面指定元素,比如: // document.getElementById('results-container').innerHTML = tableHtml; console.log('所有数据处理完成!'); } // 启动处理流程 processAllData();
额外注意事项
- API配额与限流:高级账户配额更高,但
batchSize建议设为10-20之间;如果遇到OVER_QUERY_LIMIT错误,可以在getTravelTime中添加重试逻辑(比如最多重试3次,每次间隔1秒) - 结果一致性:同一坐标对结果偶尔不一致可能是实时路况影响,可添加
departureTime参数(设置为当前时间或指定时间)获取更稳定的结果 - CSV格式兼容性:如果CSV有复杂格式(比如带引号的字段),建议用专门的CSV解析库(如
PapaParse)处理,避免手动拆分出错
内容的提问来源于stack exchange,提问作者ohhimark
相关产品推荐
相关产品推荐

