如何持续调用异步函数展示卫星位置及多场景switch case实现方案
问题修复与多场景适配方案
原有代码存在的问题
- 逻辑高度重复,两套渲染逻辑仅图标、挂载容器两个参数存在差异,维护成本高
- 未存储定时器ID,切换展示模式时无法清除旧定时器,会导致重复请求、内存泄漏
- 未销毁旧地图实例,多次切换会导致多个地图实例同时占用DOM资源,引发卡顿
- a标签未阻止默认跳转行为,点击会触发页面刷新,逻辑无法正常执行
- 状态变量(首次定位标记、标记实例、地图实例)定义在函数内部,全局无法访问,无法实现状态复用与清理
修复实现步骤
1 调整HTML结构
给所有切换链接增加自定义属性标记展示类型,统一绑定点击事件,阻止默认跳转:
<h1>Where is the ISS?</h1> <p> latitude: <span id="lat"></span>°<br> longitude: <span id="lon"></span>° </p> <div> <a class="link" data-type="1" href="javascript:void(0)">带图标展示</a>| <a class="link" data-type="2" href="javascript:void(0)">无图标展示</a>| <a class="link" data-type="3" href="javascript:void(0)">后续新增选项</a> </div> <!-- 仅保留一个地图容器即可,不需要多个 --> <div id="issMap"></div>
2 重构JS逻辑
将公共变量全局存储,封装通用渲染函数,用配置表处理多场景差异,切换前自动清理旧资源:
// 全局公共变量存储 let mapInstance = null; let markerInstance = null; let updateTimer = null; let isFirstLocation = true; const apiUrl = 'https://api.wheretheiss.at/v1/satellites/25544'; const attribution = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'; const tileUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; // 多场景配置表,新增场景仅需在这里加配置即可,无需修改核心逻辑 const renderConfig = { 1: { icon: L.icon({ iconUrl: "iss200.png", iconSize: [75, 75], }) }, 2: { icon: null }, 3: { // 后续新增场景配置,比如其他卫星图标、不同刷新频率、不同地图层级等 icon: L.icon({ iconUrl: "other-satellite.png", iconSize: [50, 50], }) } } // 清理旧资源通用函数 function clearOldResource() { // 清除定时器 if(updateTimer) clearInterval(updateTimer); // 销毁地图实例 if(mapInstance) mapInstance.remove(); // 重置首次定位标记 isFirstLocation = true; } // 通用渲染函数 async function renderISS(type) { // 先清理旧资源 clearOldResource(); // 获取当前场景配置 const config = renderConfig[type]; // 初始化地图 mapInstance = L.map('issMap').setView([0, 0], 1); L.tileLayer(tileUrl, { attribution }).addTo(mapInstance); // 初始化标记 const markerOption = config.icon ? {icon: config.icon} : {}; markerInstance = L.marker([0, 0], markerOption).addTo(mapInstance); // 更新位置逻辑 async function updatePosition() { const response = await fetch(apiUrl); const data = await response.json(); const { latitude, longitude } = data; markerInstance.setLatLng([latitude, longitude]); if (isFirstLocation) { mapInstance.setView([latitude, longitude], 5); isFirstLocation = false; } document.getElementById('lat').textContent = latitude.toFixed(3); document.getElementById('lon').textContent = longitude.toFixed(3); } // 立即执行一次,之后每秒刷新 updatePosition(); updateTimer = setInterval(updatePosition, 1000); } // 页面加载默认执行带图标展示 window.onload = () => renderISS(1); // 绑定所有链接的点击事件 document.querySelectorAll('.link').forEach(link => { link.addEventListener('click', () => { const type = link.getAttribute('data-type'); renderISS(type); }) })
多场景需求通用实现方案
- 优先使用配置表模式替代switch case,后续新增场景仅需新增配置项,无需修改核心渲染逻辑,符合开闭原则,维护成本更低
- 如果场景存在逻辑差异而非仅参数差异,可在配置表中存储对应处理函数,直接调用即可,同样不需要修改核心逻辑
- 所有状态、实例全局统一存储,切换前必须做资源清理,避免内存泄漏与性能问题
- 公共逻辑统一封装,差异化内容从配置中读取,最大程度减少重复代码
如果确实需要用switch case实现,可把配置读取部分替换为如下逻辑:
function getConfigByType(type) { switch(type) { case '1': return { icon: L.icon({ iconUrl: "iss200.png", iconSize: [75, 75], }) } case '2': return { icon: null } case '3': return { icon: L.icon({ iconUrl: "other-satellite.png", iconSize: [50, 50], }) } default: return renderConfig['1'] } }
内容的提问来源于stack exchange,提问作者user14584183
相关产品推荐
相关产品推荐

