
本文介绍如何通过定时轮询 json 数据并更新地图标记,实现车辆 gps 位置的实时刷新,重点解决数据未同步更新、旧标记残留等问题。
在基于 Google Maps JavaScript API 构建实时车辆追踪系统时,仅定时拉取新数据(fetchAPI)是不够的——若不将响应结果赋值回全局 data 变量,后续 setMarker() 函数始终渲染的是初始快照,导致地图标记“卡死”在首次加载的位置。
✅ 正确的数据流设计
首先,修正 fetchAPI:移除 return,改为直接更新共享变量 data:
let data = null; // 初始化为 null,避免未定义引用
const fetchAPI = async () => {
try {
const response = await fetch('./cradlepoint.json');
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const locations = await response.json();
data = locations; // ✅ 关键:实时覆盖 data
} catch (err) {
console.error('Failed to fetch vehicle data:', err);
}
};接着,必须清理旧标记,否则每 5 秒都会叠加新标记,造成内存泄漏与视觉混乱。推荐使用 Marker 实例数组集中管理:
let markers = []; // 存储所有活跃标记的引用
function setMarker() {
// ✅ 清除所有现有标记
markers.forEach(marker => marker.setMap(null));
markers = [];
// ✅ 确保 data 已就绪且包含有效数据
if (!data || !Array.isArray(data.data) || data.data.length === 0) return;
const busicon = "https://maps.google.com/mapfiles/ms/icons/bus.png";
const infoWindow = new google.maps.InfoWindow();
data.data.forEach(vehicle => {
const { id, latitude, longitude } = vehicle;
// ✅ 创建新标记并保存引用
const marker = new google.maps.Marker({
map,
position: { lat: latitude, lng: longitude },
icon: busicon,
title: id,
});
// ✅ 绑定点击事件(注意:infoWindow 复用,避免重复创建)
marker.addListener('click', () => {
infoWindow.close();
infoWindow.setContent(`Vehicle ID: ${id}`);
infoWindow.open(map, marker);
});
markers.push(marker); // 记录引用,便于后续清除
});
}? 启动逻辑优化(避免竞态与重复初始化)
- 不要在 initMap() 内部直接调用 setInterval(setMarker, 5000),而应在地图初始化完成、且首次数据加载成功后启动;
- 使用 Promise.all 确保地图库与初始数据并行加载:
async function initMap() {
const { Map } = await google.maps.importLibrary("maps");
const { Marker } = await google.maps.importLibrary("marker");
map = new Map(document.getElementById("map"), {
mapId: "YOUR_MAP_ID",
center: { lat: 37.7749, lng: -122.4194 }, // 示例坐标
zoom: 14,
});
// 首次加载数据并渲染
await fetchAPI();
setMarker();
// ✅ 启动轮询:先拉取新数据,再刷新标记
setInterval(async () => {
await fetchAPI(); // 等待数据更新完成
setMarker(); // 再渲染最新状态
}, 5000);
}
// 页面加载完成后初始化
window.addEventListener('load', initMap);⚠️ 注意事项与最佳实践
- 错误处理不可省略:网络失败或 JSON 格式错误会导致 data 为 undefined,setMarker() 必须做防御性检查(如 if (!data?.data?.length) return;);
- 性能考量:若车辆数量庞大(>100),考虑使用 MarkerClusterer 聚合标记;
- 服务端优化建议:生产环境应改用 WebSocket 或 Server-Sent Events(SSE)替代轮询,降低延迟与服务器压力;
- 图标与样式:busicon URL 应托管在同源或配置 CORS,否则标记可能不显示。
通过以上重构,你的地图将真正实现「数据驱动」的动态刷新——每次轮询后,旧标记被精准清除,新位置被实时呈现,为车队监控提供可靠可视化支持。










