无途经点多路线异步请求致顺序错乱及结果数组为空问题
解决Google Maps API异步路线请求的顺序错乱与结果数组为空问题
我明白你遇到的麻烦了——因为Google Maps Directions API是异步请求,循环里同时发起多个调用时,响应返回的顺序完全不确定,导致路线结果乱序,而且同步代码里打印数组的时候,异步请求还没完成,所以数组是空的。加上不能用途经点方案,得按段处理A->B、B->C、C->D的路线,我们可以用Promise结合async/await来解决这个问题,确保请求按顺序执行,结果也能正确按顺序存入数组。
问题根源分析
- 异步请求无序性:你原来的循环里同步触发多个
requestDirections,每个里面的directionsService.route是异步的,哪个请求先返回就先执行renderDirections,完全不按请求顺序来,所以routeArrayResult里的元素顺序会乱。 - 同步代码提前执行:循环里的
console.log是同步运行的,这时候所有异步请求还在等待响应,所以routeArrayResult肯定是空的。 doClickClear的隐藏问题:原来的directionsRenderer是renderDirections里的局部变量,外部的doClickClear根本访问不到,所以点击清除按钮不会生效。
完整解决方案代码
我们先把API调用封装成Promise,再用async/await按顺序发起请求,同时修复清除功能:
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <style type="text/css"> html { height: 100% } body { height: 100%; margin: 0px; padding: 0px } </style> <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3"></script> <script type="text/javascript"> var map; var routeColor; var myOptions = { zoom:7, mapTypeId: google.maps.MapTypeId.ROADMAP, }; var routeArray = ['61.84448683734486, 8.85223388671875', '61.75298123367897, 9.078826904296875', '61.484039,7.645798', '61.944118091023746,7.97882080078125']; var routeArrayResult = []; var routeColorArray = ['#ff00ff', '#40ff00', '#0040ff', '#ffbf00', '#00ffff', '#ff00ff', '#ff8000']; const directionsRenderers = []; // 存储所有路线渲染实例,用于清除 function initMap() { map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); } function renderDirections(result, order) { const directionsRenderer = new google.maps.DirectionsRenderer({ suppressMarkers: true, suppressInfoWindows: true // 修复原代码的拼写错误:suppresInfoWindows }); directionsRenderer.setOptions({ polylineOptions: { strokeWeight: 3, strokeOpacity: 0.5, strokeColor: routeColorArray[order] // 绑定对应顺序的颜色 } }); directionsRenderer.setMap(map); directionsRenderer.setDirections(result); directionsRenderers.push(directionsRenderer); // 保存实例到数组 const route = result.routes[0]; const summaryPanel = document.getElementById("directions_panel"); const routeInfo = `Route ${order + 1} distance:${route.legs[0].distance.text}`; routeArrayResult.push(routeInfo); summaryPanel.innerHTML += `${routeInfo}<br>`; console.log(`Render - Push result to Array id:${order + 1}`); } // 把Directions API调用封装成Promise function getDirections(start, end) { return new Promise((resolve, reject) => { const directionsService = new google.maps.DirectionsService(); const request = { origin: start, destination: end, travelMode: google.maps.DirectionsTravelMode.DRIVING, drivingOptions: { departureTime: new Date("08/08/2018") } }; directionsService.route(request, (result, status) => { if (status === google.maps.DirectionsStatus.OK) { resolve(result); } else { reject(new Error(`Directions request failed: ${status}`)); } }); }); } // 用async/await按顺序发起请求 async function doClick3() { routeArrayResult = []; const summaryPanel = document.getElementById("directions_panel"); summaryPanel.innerHTML = ""; // 先清除之前的路线 directionsRenderers.forEach(r => r.setMap(null)); directionsRenderers.length = 0; for (let i = 0; i < routeArray.length - 1; i++) { routeColor = routeColorArray[i]; console.log(`doclick3 [${i}] From:${routeArray[i]} To:${routeArray[i+1]} in color ${routeColor}`); try { // 等待当前请求完成后再发起下一个 const result = await getDirections(routeArray[i], routeArray[i+1]); renderDirections(result, i); } catch (error) { alert(error.message); } } // 所有请求完成后再打印结果,此时数组已填充完整 console.log("Total resultslength: " + routeArrayResult.length + " total routes:" + (routeArray.length - 1)); console.log("routeArrayResult: ", routeArrayResult); } function doClickClear() { directionsRenderers.forEach(renderer => { renderer.setMap(null); }); directionsRenderers.length = 0; routeArrayResult = []; document.getElementById("directions_panel").innerHTML = ""; } </script> </head> <body onload="initMap()"> <div id="map_canvas" style="float:left;width:70%;height:100%;"></div> <div id="control_panel" style="float:right;width:30%;text-align:left;padding-top:20px"> <input type="button" name="resetButton" onclick="doClick3();" value="calc 3 routes"> <input type="button" name="resetButton" onclick="doClickClear();" value="clear routes"> <div id="directions_panel" style="margin:20px;background-color:#FFEE77;"></div> </div> </body> </html>
关键改进点说明
- Promise封装API调用:把
directionsService.route包装成返回Promise的函数getDirections,这样就能用async/await来控制异步流程。 - async/await顺序执行:
doClick3改成async函数,循环里用await等待每个请求完成后再处理下一个,确保路线请求和结果存入数组的顺序完全和A->B、B->C、C->D一致。 - 修复清除功能:用数组
directionsRenderers存储所有创建的DirectionsRenderer实例,清除时遍历数组把每个实例从地图上移除,同时清空数组和结果数组。 - 修复拼写错误:原代码里的
suppresInfoWindows改成正确的suppressInfoWindows,避免功能异常。 - 延迟结果打印:把数组长度的打印放在循环结束后,确保所有异步请求都完成,此时
routeArrayResult已经填充了所有路线信息。
这样修改后,你就能得到顺序完全正确的路线结果数组,而且不会再出现数组为空的问题了。
内容的提问来源于stack exchange,提问作者Lesley Persyn
相关产品推荐
相关产品推荐

