【问题标题】:Unable to add Google markers inside a loop无法在循环内添加 Google 标记
【发布时间】:2020-06-26 17:43:49
【问题描述】:

所以,我从我的 firestore 数据库中获取地址,将它们转换为坐标,然后尝试根据每组坐标添加标记。我可以在循环外添加标记,但不能在循环内添加。

谢谢

    //Convert addresses to coords
    //Fetch all addresses from db
    db.collection('specials').get()
    .then(snapshot => {
        snapshot.forEach(special => {
            //Set location
            var location = special.data().address;

            //Get geocode info
            axios.get('https://maps.googleapis.com/maps/api/geocode/json?components=country:NZ|country:AU',{
                params:{
                    address:location, 
                    key:'************************************',  
                }
            })
            .then(function(response){
                //Geometry
                markerLat = response.data.results[0].geometry.location.lat;
                markerLng = response.data.results[0].geometry.location.lng; 

                //console.log("Lat:" + markerLat + " Lng:" + markerLng);

                //Doesn't work inside the loop
                markers.push({
                    coords:{lat: markerLat, lng: markerLng}
                });

            })
        });
    })

    //Works outside the loop
    markers.push({
        coords:{lat: -36.8585, lng: 174.7833}
    });

【问题讨论】:

  • 你能澄清你的问题吗?当您说它“在循环内不起作用”时,您是什么意思?你如何测试它?您确定要考虑地理编码器的异步性质吗?请提供一个 minimal reproducible example 来证明您的问题。
  • @James:我的回答有什么帮助吗?你有进步吗?

标签: javascript arrays google-maps google-cloud-firestore


【解决方案1】:

我的第一个猜测是您在循环之外使用 markers,例如在调用地图 API 时。这是行不通的,因为数据是从 Firestore 异步加载的,此时数据还不可用。

了解异步加载如何工作的最简单方法是使用一些放置良好的日志语句:

console.log("1. Before calling database");
db.collection('specials').get()
.then(snapshot => {
    console.log("2. Got database results, calling geocode API");
    snapshot.forEach(special => {
        var location = special.data().address;
        axios.get('https://maps.googleapis.com/maps/api/geocode/json?components=country:NZ|country:AU',{
            params:{ address:location,  key:'********' }
        })
        .then(function(response){
            console.log("3. Got geocode result");
        })
    });
})
console.log("4. After calling database");

现在,当您运行此代码时,日志输出将是:

  1. 调用数据库之前

  2. 调用数据库后

  3. 得到数据库结果,调用geocode API

  4. 得到地理编码结果

  5. 得到地理编码结果

...

这可能不是您所期望的,因为代码没有按照您在文件中的顺序执行。但由于异步 API 的性质,它完全按预期工作。并且,它解释了为什么不将数据库中的位置添加到地图中,如果您对地图的调用接近于记录语句 4.:到运行时,尚未从数据库中加载任何数据,并且地理编码还没有还没有完成。

任何需要数据库数据的代码都应该在then 回调中。让事情变得更复杂:由于您还希望完成所有地理查找,因此您只想在所有嵌套的 then() 调用发生后将标记添加到地图。

为此,您可以使用Promise.all,它会在解决多个其他then() 调用后解决单个then()

结合所有这些,代码应该看起来像这样:

//Fetch all addresses from db
db.collection('specials').get()
.then(snapshot => {
    // Get all addresses from the documents
    return snapshot.docs.map(doc => doc.data().address);
})
.then(addresses => {
    // Geocode all addresses, to get coordinates
    return Promise.all(addresses.map(location => {
        return axios.get('https://maps.googleapis.com/maps/api/geocode/json?components=country:NZ|country:AU',{
            params:{
                address:location, 
                key:'************************************',  
            }
        })
    });
})
.then(locations => {
    // Convert all geometry into markers
    return locations.map(response => {
        markerLat = response.data.results[0].geometry.location.lat;
        markerLng = response.data.results[0].geometry.location.lng; 

        return  {
            coords:{lat: markerLat, lng: markerLng}
        });
    });
})
.then(markers => {
    // TODO: call the maps API and add the markers
});

如果您的代码在现代 JavaScript 环境中运行,您可以使用 async/await 使上述读取更正常。

//Fetch all addresses from db
let snapshot = await db.collection('specials').get()

// Get all addresses from the documents
let addresses = snapshot.docs.map(doc => doc.data().address);

// Geocode all addresses, to get coordinates
let locations = await Promise.all(addresses.map(location => {
    return axios.get('https://maps.googleapis.com/maps/api/geocode/json?components=country:NZ|country:AU',{
        params:{
            address:location, 
            key:'************************************',  
        }
    })
});

// Convert all geometry into markers
let markers = locations.map(response => {
    markerLat = response.data.results[0].geometry.location.lat;
    markerLng = response.data.results[0].geometry.location.lng; 

    return  {
        coords:{lat: markerLat, lng: markerLng}
    });
});

// TODO: call the maps API and add the markers

正如您在此处看到的,结构大体相同,我们大多只是使用 await 关键字去除了 then 块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-29
    • 2017-12-18
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 2014-10-20
    相关资源
    最近更新 更多