您好我正在开发一个谷歌地图项目,我正在绘制一个旅程,我正在使用AJAX请求将数据作为一个对象数组返回,然后我循环遍历该数组并创建一个新的latlng对象数组如下所示,这一切都很完美
var pathCoords = [];
for (var i = 0; i < Object.keys(data).length; i++) {
route = {
lat : data[i].latitude,
lng : data[i].longitude
}
pathCoords.push(route);
}
我接下来绘制开始和结束标记,这很好,然后我循环遍历pathCoords []
并沿折线绘制移动标记。见下面的方法
for (i = 0; i < pathCoords.length; i++) {
setTimeout(function(coords) {
var latlng = new google.maps.LatLng(coords.lat, coords.lng);
routeLine.getPath().push(latlng);
moveMarker(map, marker, latlng);
if(i === (Object.keys(data).length-1)){
console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
}
//console.log("data link...."+Object.keys(data).length)
}, 200 * i, pathCoords[i]);
moveMarker执行它所说的操作,移动标记,我想要实现的是调用方法,当for循环结束时调用<{1}} ,此方法相应地适应和集中地图,我已经搜索并尝试了所有内容,并且无法弄清楚这一点,我也尝试了来自其他答案的SO解决方案,这只是不起作用,如下面的方法。
centerMapandZoom(markerStart,markerEnd,pathCoords);
任何帮助或解决方案,我基本上都试图在地图上填写路线和标记,说我尝试使用if(i === (Object.keys(data).length-1)){
console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
}
,这对我也没帮助,谢谢
答案 0 :(得分:2)
我会利用Promise.all
的承诺来处理这个问题,它看起来像这样:
function delayedMarkerPlace(i) {
return new Promise(resolve => {
setTimeout(() => {
// place the marker
resolve();
}, 200 * i)
});
}
const placeMarkersPromises = [];
for (var i = 0; i < Object.keys(data).length; i++) {
placeMarkersPromises.push(delayedMarkerPlace(i));
}
Promise.all(placeMarkersPromises).then(() => {
// action after all markers have been placed
});
答案 1 :(得分:1)
您正在循环中创建一个函数,这意味着i的值是通过引用捕获的,这意味着当执行超时函数时i的值与创建函数时的值不同。
尝试在循环之外创建函数并传递它需要的所有信息,例如:(不,我没有测试过这个,但我希望它可以解决这个问题。)
var on_call = function(coords, j, end_index) {
var latlng = new google.maps.LatLng(coords.lat, coords.lng);
routeLine.getPath().push(latlng);
moveMarker(map, marker, latlng);
if(j === end_index){
console.log("This is the end..."+i+"coordinates size "+end_index + 1);
centerMapandZoom(markerStart,markerEnd,pathCoords);
}
}
for (i = 0; i < pathCoords.length; i++) {
setTimeout(on_call , 200 * i, pathCoords[i], j, pathCoords.length -1);
在循环中创建一个函数是你想要避免很多时间的事情,因为闭包可能会导致一开始看起来很奇怪的错误。
建议阅读:http://javascriptissexy.com/understand-javascript-closures-with-ease/
答案 2 :(得分:1)
因为您已为后续功能
创建了闭包 for (i = 0; i < pathCoords.length; i++) {
setTimeout(function(coords) {
var latlng = new google.maps.LatLng(coords.lat, coords.lng);
routeLine.getPath().push(latlng);
moveMarker(map, marker, latlng);
if(i === (Object.keys(data).length-1)){
console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
}
//console.log("data link...."+Object.keys(data).length)
}, 200 * i, pathCoords[i]);
}
这里setTimeout是异步的,所以第一次遇到for循环时, 它将函数放入池中以在超时后执行并继续执行代码,以便循环继续和下一个并且相同直到达到长度,
现在在函数执行超时后,它可以访问外部作用域变量i,现在已经等于长度。在第一次条件检查时
i === (Object.keys(data).length-1) // i is already equals to length-1,
解决方案是使用iife
for (i = 0; i < pathCoords.length; i++) {
(function(i){
setTimeout(function(coords) {
var latlng = new google.maps.LatLng(coords.lat, coords.lng);
routeLine.getPath().push(latlng);
moveMarker(map, marker, latlng);
if(i === (Object.keys(data).length-1)){
console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
}
//console.log("data link...."+Object.keys(data).length)
}, 200 * i, pathCoords[i]);
}(i))
}
答案 3 :(得分:1)
在JavaScript中,函数创建自己的执行上下文。因此,每次调用函数时,都会创建一个新的执行上下文。如果您创建一个setTimeout函数,该函数将异步运行,这意味着JavaScript引擎将继续逐行解析并执行您的代码,而无需等待您的计时器函数返回。这意味着您丢失了想要分配给变量i的任何值,只是因为您没有在该特定执行上下文或范围中捕获其值。因此,为了捕获该值,您必须创建一个闭包。使用闭包,您可以将代码包含在一个函数中,创建一个具有自己的执行上下文的本地作用域,从而允许您获取i的值。
for (i = 0; i < pathCoords.length; i++) {
// this is how you do not lose the value of i
// waiting for setTimeout to return
(function(i){
// note the above function has a closure over setTimeout
// this is where the magic happens because here you create the
// execution context or local scope you want to "link" the iteration
// to the timer function
setTimeout(function(coords) {
var latlng = new google.maps.LatLng(coords.lat, coords.lng);
routeLine.getPath().push(latlng);
moveMarker(map, marker, latlng);
if(i === (Object.keys(data).length-1)){
console.log("This is the end..."+i+"co=ordinates size" +pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
}
}, 200 * i, pathCoords[i]);
// the IIFE function gets executed and you pass an
// argument that will equal i when passed as a parameter
// inside the IIFE function
}(i))
}
在现代浏览器中,您还可以通过将LET声明用作for循环中的变量来创建局部作用域,如下所示:
for (let i = 0; i < whatever.length; i++){
whatever you want;
}
这意味着您将为您的问题提供更优雅的解决方案,其缺点是旧版浏览器可能不支持。换句话说,它需要测试。你可以为闭包实现其他解决方案,但那些更多&#34;冗长&#34;写作和解释,但如果您需要其他解释或示例,请告诉我。