You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Maps API脚本多维数组控制台验证后返回undefined问题排查

问题根源:异步操作的时序坑

你碰到的这个问题核心在于Google Maps地理编码API的请求是异步执行的,而你在$.post回调里的第二个for循环是同步跑的——当循环尝试访问markers[i][0]时,geocodeAddress里的地理编码请求还没完成,对应的markers[i]根本还没被赋值,自然会抛出TypeError: x[r] is undefined。

至于控制台能看到markers数组有6个元素,是因为浏览器控制台会实时更新引用类型的显示:你看到的是所有异步请求完成后的数组状态,而不是循环执行那一刻的状态,属于典型的“控制台欺骗”。


解决方案:等所有异步请求完成再处理标记

这里给你两种实用的解决思路,推荐第二种(Promise方案),更符合现代JS的写法:

方案1:用计数器追踪异步完成状态

在回调作用域内设置一个计数器,每次地理编码成功(或失败)后递增,当计数器等于预期的标记数量时,再执行处理markers的逻辑:

if ($('#propertymap').length){
    var map=new google.maps.Map(document.getElementById('propertymap'), {
        center: {lat: 37.09024, lng: -95.712891},
        zoom: 5
    });
    var bounds=new google.maps.LatLngBounds();
    var geocoder=new google.maps.Geocoder();
    var markers=[];
    var infocontent=[];
    // 新增计数器
    var completedGeocodes = 0;
    var totalLocations;

    $.post('/_getproperties.php', {task:'getproperties'}, function(result){
        var locationsSplit=result.replace('{', '').split('}');
        totalLocations = locationsSplit.length - 1;
        
        for (var i=0; i<totalLocations; i++){
            var currentFields=locationsSplit[i].split('|');
            var id=currentFields[0];
            var location=currentFields[1];
            var street=currentFields[2];
            var city=currentFields[3];
            var state=currentFields[4];
            var zip=currentFields[5];
            var squarefootage=currentFields[6];
            var ownedacreage=currentFields[7];
            var leasedacreage=currentFields[8];
            var hotelrooms=currentFields[9];
            var website=currentFields[10];
            
            geocodeAddress(location, street + ', ' + city + ', ' + state + ' ' + zip, location + '<br />' + street + '<br />' + city + ', ' + state + ' ' + zip, i);
        }
    });

    function geocodeAddress(locationtitle, locationaddress, locationdescription, i){
        geocoder.geocode({'address': locationaddress}, function(results, status){
            if (status==='OK'){
                markers[i]=[];
                markers[i][0]=locationtitle;
                markers[i][1]=results[0].geometry.location.lat();
                markers[i][2]=results[0].geometry.location.lng();
                infocontent[i]=[];
                infocontent[i][0]=locationdescription;
            } else {
                console.log('Geocode was not successful for the following reason: ' + status);
            }
            // 无论成功失败都递增计数器,避免无限等待
            completedGeocodes++;
            // 所有异步请求完成后处理标记
            if (completedGeocodes === totalLocations) {
                processMarkers();
            }
        });
    }

    // 封装处理标记的逻辑
    function processMarkers() {
        console.log(markers);
        console.log(infocontent);
        for (var i=0; i<markers.length; i++){
            console.log(i);
            console.log(markers[i][0]);
            // 这里还可以继续添加创建地图标记、绑定信息窗口的逻辑
        }
    }
}

方案2:用Promise.all管理所有异步请求

把每个地理编码请求包装成Promise,然后用Promise.all等待所有请求完成后再处理,代码结构更清晰:

if ($('#propertymap').length){
    var map=new google.maps.Map(document.getElementById('propertymap'), {
        center: {lat: 37.09024, lng: -95.712891},
        zoom: 5
    });
    var bounds=new google.maps.LatLngBounds();
    var geocoder=new google.maps.Geocoder();

    $.post('/_getproperties.php', {task:'getproperties'}, function(result){
        var locationsSplit=result.replace('{', '').split('}');
        var totalLocations = locationsSplit.length - 1;
        // 存储所有Promise
        var geocodePromises = [];

        for (var i=0; i<totalLocations; i++){
            var currentFields=locationsSplit[i].split('|');
            var location=currentFields[1];
            var street=currentFields[2];
            var city=currentFields[3];
            var state=currentFields[4];
            var zip=currentFields[5];
            var locationaddress = street + ', ' + city + ', ' + state + ' ' + zip;
            var locationdescription = location + '<br />' + street + '<br />' + city + ', ' + state + ' ' + zip;

            // 把每个地理编码请求包装成Promise
            var promise = new Promise((resolve, reject) => {
                geocoder.geocode({'address': locationaddress}, function(results, status){
                    if (status==='OK'){
                        resolve({
                            title: location,
                            lat: results[0].geometry.location.lat(),
                            lng: results[0].geometry.location.lng(),
                            info: locationdescription
                        });
                    } else {
                        reject('Geocode was not successful for the following reason: ' + status);
                    }
                });
            });
            geocodePromises.push(promise);
        }

        // 等待所有Promise完成
        Promise.all(geocodePromises)
            .then((markersData) => {
                // markersData是所有成功的地理编码结果数组
                console.log(markersData);
                markersData.forEach((data, i) => {
                    console.log(i);
                    console.log(data.title);
                    // 这里可以创建地图标记:
                    // var marker = new google.maps.Marker({
                    //     position: {lat: data.lat, lng: data.lng},
                    //     map: map,
                    //     title: data.title
                    // });
                    // 绑定信息窗口等逻辑
                });
            })
            .catch((error) => {
                console.error(error);
            });
    });
}

额外提示
  1. 注意Google Maps地理编码API有请求配额限制,批量请求时要避免触发限制;
  2. 你的locationsSplit字符串分割逻辑比较脆弱,如果后端返回的格式有变化(比如多了空格)就容易出错,建议后端直接返回JSON格式,前端用JSON.parse解析,比字符串分割靠谱得多。

内容的提问来源于stack exchange,提问作者BB Design

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:18:06