求助:JavaScript嵌套函数返回距离值首次执行undefined,二次执行正常
解决Google Maps DirectionsService首次获取距离返回undefined的问题
嘿,我太懂这个坑了!你遇到的问题完全是因为Google Maps的DirectionsService.route()是异步操作导致的——这可是前端开发里新手常踩的经典陷阱😅
问题根源拆解
先看你代码的核心逻辑:你定义了全局变量Distance,然后在calcRoute()里调用directionsService.route()请求路线数据。但这个方法不会立刻返回结果,它会在后台发送请求,等Google服务器返回数据后才会触发回调函数,在回调里给Distance赋值。
而你大概率是在调用calcRoute()之后立刻去读取Distance——这时候异步请求还没完成,回调函数根本没执行,Distance自然还是初始的undefined。第二次执行时,第一次的异步请求已经完成,Distance被成功赋值,所以就能拿到正确值了。
举个更直观的简化版代码示例:
var directionsService = new google.maps.DirectionsService(); var Distance; function calcRoute() { var source = document.getElementById("txtSource").value; var destination = document.getElementById("txtDestination").value; var request = { origin: source, destination: destination, travelMode: google.maps.TravelMode.DRIVING }; // 异步请求:这行代码立刻执行,但回调要等服务器响应才触发 directionsService.route(request, function(response, status) { if (status == google.maps.DirectionsStatus.OK) { Distance = response.routes[0].legs[0].distance.value; } }); } // 调用后立刻读Distance,此时回调还没执行! calcRoute(); console.log(Distance); // 第一次输出undefined,第二次可能有值
靠谱的解决方案
解决异步问题的核心思路是:不要在异步操作完成前试图获取结果,必须等回调触发后再处理数据。这里给你两种常用的写法:
方案1:用回调函数传递结果
把需要用到距离的逻辑直接放到回调里,或者传入一个自定义回调函数,让异步结果触发后再执行你的业务逻辑:
var directionsService = new google.maps.DirectionsService(); function calcRoute(callback) { var source = document.getElementById("txtSource").value; var destination = document.getElementById("txtDestination").value; var request = { origin: source, destination: destination, travelMode: google.maps.TravelMode.DRIVING }; directionsService.route(request, function(response, status) { if (status == google.maps.DirectionsStatus.OK) { var distance = response.routes[0].legs[0].distance.value; callback(null, distance); // 成功时把结果传给回调 } else { callback(new Error(`获取路线失败:${status}`), null); // 失败时传递错误 } }); } // 调用方式:只有当异步请求完成后,才会执行这里的逻辑 calcRoute(function(err, distance) { if (err) { console.error(err); return; } console.log("计算得到的距离:", distance); // 在这里写你需要用距离做的事情,比如更新页面、计算费用等 });
方案2:用Promise封装(更现代的写法)
把异步操作封装成Promise,这样可以用then()链式调用,或者更简洁的async/await语法:
var directionsService = new google.maps.DirectionsService(); function calcRoute() { return new Promise((resolve, reject) => { var source = document.getElementById("txtSource").value; var destination = document.getElementById("txtDestination").value; var request = { origin: source, destination: destination, travelMode: google.maps.TravelMode.DRIVING }; directionsService.route(request, function(response, status) { if (status == google.maps.DirectionsStatus.OK) { var distance = response.routes[0].legs[0].distance.value; resolve(distance); // 成功时返回结果 } else { reject(new Error(`获取路线失败:${status}`)); // 失败时抛出错误 } }); }); } // 方式一:用then()链式调用 calcRoute() .then(distance => { console.log("计算得到的距离:", distance); // 处理距离相关逻辑 }) .catch(err => console.error(err)); // 方式二:用async/await(需要在async函数内使用) async function getDistance() { try { const distance = await calcRoute(); console.log("计算得到的距离:", distance); // 处理距离相关逻辑 } catch (err) { console.error(err); } } getDistance();
最后提醒
尽量不要用全局变量存储异步操作的结果,这种写法很容易出现时序问题,而且代码可读性差。用回调、Promise或者async/await才是处理异步逻辑的标准方式,能让你的代码更可靠、更易维护~
内容的提问来源于stack exchange,提问作者Ranjit Singh Shekhawat
相关产品推荐
相关产品推荐

