d3.csv读取的全局数组在函数外部显示undefined问题求助
问题:全局数组在函数外部显示undefined,无法加载CSV数据到Google地图标记
使用D3.js v7和Google Maps JavaScript API时,声明了全局数组存储CSV数据,但在读取函数外部访问数组元素时显示undefined,无法生成地图标记。CSV格式为Project_Name, Artist, Lat, Long,包含约300条数据。
原代码如下:
// Request needed libraries. const { Map, InfoWindow } = await google.maps.importLibrary("maps"); const { LatLng } = await google.maps.importLibrary("core"); const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker"); //Global Vars let map; let projectName = []; let artist = []; let lat = []; let long = []; let markers = []; async function data() { d3.csv("/data/single.csv", function(d) { return { projectName: +d.Project_Name, artist: +d.Artist, lat: +d.Latitude, long: +d.Longitude, } }).then(function(d) { for (var i = 0; i < d.length; i++) { projectName[i] = d[i].Project_Name; artist[i] = d[i].Artist; lat[i] = parseFloat(d[i].Latitude); long[i] = parseFloat(d[i].Longitude); } }); } function createMarkers(m){ for (var z=0; z < lat.length; z++) { markers[z] = new google.maps.Marker({ position: new google.maps.LatLng(lat[z], long[z]), map: m, title: projectName[z], }); } } async function initMap() { const map = new Map(document.getElementById("map"), { zoom: 11, center: { lat: 37.4239163, lng: -122.0947209 }, mapId: "[MAP ID]", mapTypeControl: false, }); const infoWindow = new google.maps.InfoWindow({ content: "", disableAutoPan: true, }); //READ CSV FILE data(); //MARKERS createMarkers(map); } initMap();
尝试过await和setTimeout但未解决,使用setTimeout后值变为NaN。
解决方案
问题根源
- 异步执行顺序错误:
data()是异步函数但未返回Promise,且initMap中调用data()时没有等待其执行完成,导致createMarkers先运行,此时全局数组还未被CSV数据填充,因此显示undefined。 - D3数据转换错误:在
d3.csv的转换函数中,用+将Project_Name和Artist(字符串类型)强制转为数字,导致这两个字段变成NaN,后续赋值自然无法得到正确内容。
修改步骤
- 修复D3数据转换逻辑:移除
Project_Name和Artist前的+,保留字符串类型;Latitude和Longitude直接用+转数字,无需后续再调用parseFloat。 - 让
data()返回Promise:直接返回d3.csv的调用结果,确保可以用await等待数据加载完成。 - 在
initMap中等待data()完成:调用data()时添加await,确保数组填充完成后再执行createMarkers。
修改后的完整代码
// Request needed libraries. const { Map, InfoWindow } = await google.maps.importLibrary("maps"); const { LatLng } = await google.maps.importLibrary("core"); const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker"); //Global Vars let map; let projectName = []; let artist = []; let lat = []; let long = []; let markers = []; // 修改data函数,返回Promise并修复数据转换 async function data() { return d3.csv("/data/single.csv", function(d) { return { projectName: d.Project_Name, // 去掉+,保留字符串 artist: d.Artist, // 去掉+,保留字符串 lat: +d.Latitude, // 直接转数字 long: +d.Longitude // 直接转数字 } }).then(function(d) { for (var i = 0; i < d.length; i++) { projectName[i] = d[i].projectName; artist[i] = d[i].artist; lat[i] = d[i].lat; long[i] = d[i].long; } }); } function createMarkers(m){ for (var z=0; z < lat.length; z++) { markers[z] = new google.maps.Marker({ position: new google.maps.LatLng(lat[z], long[z]), map: m, title: projectName[z], }); } } async function initMap() { const map = new Map(document.getElementById("map"), { zoom: 11, center: { lat: 37.4239163, lng: -122.0947209 }, mapId: "[MAP ID]", mapTypeControl: false, }); const infoWindow = new google.maps.InfoWindow({ content: "", disableAutoPan: true, }); // 等待数据加载完成 await data(); // 数据填充后再创建标记 createMarkers(map); } initMap();
进一步优化建议
可以去掉全局数组,直接将D3返回的数据传递给createMarkers,避免全局变量带来的潜在问题:
async function data() { return d3.csv("/data/single.csv", function(d) { return { projectName: d.Project_Name, artist: d.Artist, lat: +d.Latitude, long: +d.Longitude } }); } // 修改createMarkers,直接接收数据数组 function createMarkers(m, data){ data.forEach(item => { const marker = new google.maps.Marker({ position: new google.maps.LatLng(item.lat, item.long), map: m, title: item.projectName, }); markers.push(marker); }); } async function initMap() { // ... 地图初始化代码 ... // 获取数据后直接传递给createMarkers const csvData = await data(); createMarkers(map, csvData); }
内容的提问来源于stack exchange,提问作者Sydney Linford
相关产品推荐
相关产品推荐

