

新闻资讯
技术学院本文详解 d3 v7 中 `d3.csv()` 的异步特性导致全局数组在函数外仍为 `undefined` 的根本原因,并提供基于 `async/await` 的标准解决方案,确保数据加载完成后再执行地图标记等依赖操作。
D3 v7 的 d3.csv() 返回一个 Promise,而非同步填充数据——这是问题的核心。您声明了全局数组(如 projectName = []),并在 data() 函数中尝试赋值,但由于未等待 Promise 解析完成,createMarkers() 就已执行,此时全局数组仍是空的(访问 lat[z] 自然得到 undefined,进而导致 NaN 或报错)。
要修复此问题,必须让 initMap() 等待 CSV 加载完毕。关键修改有三处:
以下是修正后的完整代码(含健壮性增强):
// 请求 Google Maps 库
const { Map, InfoWindow } = await google.maps.importLibrary("maps");
const { LatLng } = await google.maps.importLibrary("core");
const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker");
// 全局数组(保持声明)
let projectName = [];
let artist = [];
let lat = [];
let long = [];
let markers = [];
// ✅ 修正:data() 返回 Promise,使用 d3.csv 的现代解析方式
async function data() {
return d3.csv("/data/single.csv", (d) => ({
projectName: d.Project_Name, // 字符串,勿用 +d.Project_Name(会转 NaN)
artist: d.Artist,
lat: parseFloat(d.Latitude), // 显式 parseFloat 更安全
long: parseFloat(d.Longitude),
}));
}
// ✅ 修正:createMarkers 接收 map 参数,避免作用域
问题
function createMarkers(m) {
for (let z = 0; z < lat.length; z++) {
if (isNaN(lat[z]) || isNaN(long[z])) continue; // 跳过无效坐标
markers.push(
new google.maps.Marker({
position: { lat: lat[z], lng: long[z] }, // 直接传对象,更简洁
map: m,
title: projectName[z] || "Unknown Project",
})
);
}
}
// ✅ 修正:initMap 使用 async/await,确保顺序执行
async function initMap() {
const map = new Map(document.getElementById("map"), {
zoom: 11,
center: { lat: 37.4239163, lng: -122.0947209 },
mapId: "[MAP ID]",
mapTypeControl: false,
});
try {
// ? 关键:等待 CSV 加载并填充全局数组
const csvData = await data();
// 填充全局数组(推荐:直接赋值,避免手动循环索引)
projectName = csvData.map(d => d.projectName);
artist = csvData.map(d => d.artist);
lat = csvData.map(d => d.lat);
long = csvData.map(d => d.long);
// 创建标记
createMarkers(map);
} catch (error) {
console.error("CSV 加载失败:", error);
alert("地图数据加载异常,请检查 CSV 文件路径和格式。");
}
}
initMap();注意事项与最佳实践:
遵循以上模式,即可彻底解决“全局数组在异步加载后仍为 undefined”的问题,确保地理数据与地图渲染的严格时序依赖。