JavaScript 中数组显示为空但实际有内容:理解异步加载与引用传递问题

花韻仙語

花韻仙語

2026-07-25

475人浏览

原创

JavaScript 中数组显示为空但实际有内容:理解异步加载与引用传递问题

当你在控制台看到数组非空(如 [] 下展开显示子项),但 JSON.stringify() 返回空数组、访问 arr[0] 得到 undefined,根本原因通常是:数组被正确填充,但你尝试读取时它尚未完成异步填充——即读取发生在回调执行前,属于典型的“竞态条件”问题。

当你在控制台看到数组非空(如 [] 下展开显示子项),但 json.stringify() 返回空数组、访问 arr[0] 得到 undefined,根本原因通常是:**数组被正确填充,但你尝试读取时它尚未完成异步填充——即读取发生在回调执行前,属于典型的“竞态条件”问题。**

问题本质:异步加载 vs 同步访问

你的 L.GPX 插件通过 XMLHttpRequest 异步加载 GPX 文件,并在 req.onreadystatechange 回调中解析数据、调用 _addGPX → parse_trkseg → 最终执行 Gpx_Array.push(coords)。这意味着:

  • Gpx_Array.push(...) 只在 XML 加载完成、DOM 解析完毕后才触发
  • 而你在主逻辑中紧随 new L.GPX(...) 之后立即 console.log(Gpx_Array) 或 Gpx_Array[0] —— 此时请求可能刚发出,甚至尚未返回,数组仍是空的;
  • 浏览器开发者工具的 console.log(Gpx_Array) 显示展开后的结构,是因为它延迟求值(lazy evaluation):点击展开时才真正读取当前值,此时异步回调早已执行完毕,所以能看到内容;而 JSON.stringify() 是立即序列化,此时数组仍为空。

✅ 这就是为什么 console.log(Gpx_Array) 看似有数据,但 JSON.stringify(Gpx_Array) 和 Gpx_Array[0] 却是空或 undefined。

正确解决方案:基于事件或 Promise 的同步协调

不要依赖全局变量 + 手动计数 + localStorage(低效且不可靠),而是利用插件已有的事件机制:

✅ 推荐方案:监听 'loaded' 事件(最优雅)

L.GPX 在数据加载并解析完成后会触发 'loaded' 事件。你应该在此事件回调中安全访问 Gpx_Array:

// 声明全局或模块级数组(确保作用域可访问)
let Gpx_Array = [];

// 初始化 GPX 图层
const track = new L.GPX('tracce_gpx/Ovaro(MonteZoncolan)_Sutrio.gpx', {
  async: true,
  display_wpt: false,
  color: '#f5f5de',
  opacity: 0.4,
  weight: 6
});

// 关键:在 'loaded' 事件中读取数据
track.on('loaded', function() {
  console.log('GPX fully loaded!');
  console.log('Gpx_Array length:', Gpx_Array.length); // ✅ 此时必为预期值
  console.log('First segment:', Gpx_Array[0]);         // ✅ 可安全访问
  console.log('JSON:', JSON.stringify(Gpx_Array, null, 2)); // ✅ 正常输出

  // ✅ 在此处执行所有依赖 GPX 数据的逻辑
  // 例如:渲染额外图表、计算路径统计、导出坐标等
});

// 将图层添加到地图(注意:事件监听必须在 addLayer 之前或之后均可,但需在 loaded 触发前绑定)
track.addTo(Video);

同时,修改你的 parse_trkseg 方法,将 coords 推入 Gpx_Array(你注释掉了这行):

Java JDK 25
Java JDK 25

Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。

下载
parse_trkseg: function (line, xml, options, tag) {
  // ... 原有解析逻辑 ...
  var coords = [];
  for (var i = 0; i <h4>⚠️ 注意事项</h4>
  • 避免全局污染:Gpx_Array 应声明在闭包或模块作用域内,而非挂载到 window。若需多实例支持,可将数组作为 L.GPX 实例属性:

    initialize: function (gpx, options) {
      L.Util.setOptions(this, options);
      this._gpx = gpx;
      this._layers = {};
      this.gpxSegments = []; // ✅ 实例专属数组
      if (gpx) {
        this.addGPX(gpx, options, this.options.async);
      }
    },
    // 在 parse_trkseg 中使用:this.gpxSegments.push(coords);
  • localStorage 方案为何不推荐?
    localStorage.setItem(key, value) 会自动将 value 转为字符串(调用 toString()),对数组会变成 "[object Object],[object Object],...",丢失全部结构和嵌套属性。你当前能“工作”是因为浏览器调试时复制对象是深拷贝快照,并非 localStorage 真正存下了可用数据——后续 getItem() 返回的是无意义字符串,无法 JSON.parse() 恢复。

  • 不要用 setTimeout 或轮询:这是反模式,既不可靠又损害性能。

总结

现象 根本原因 正确做法
console.log(arr) 展开可见内容,但 arr[0] 为 undefined 异步加载未完成,读取过早 在 'loaded' 事件回调中访问
JSON.stringify(arr) 返回 [] 序列化发生在填充前 同上,等待事件触发
依赖 localStorage 临时存储 数据被强制转为字符串,结构丢失 使用实例属性 + 事件驱动

遵循事件驱动范式,不仅能解决当前问题,还能让代码更健壮、可维护、符合现代 JavaScript 异步编程规范。

Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南

相关专题

更多
js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

2389

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

718

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

2184

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

638

4

JavaScript转义字符
JavaScript转义字符

JavaScript中的转义字符是反斜杠和引号,可以在字符串中表示特殊字符或改变字符的含义。本专题为大家提供转义字符相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.04

1167

5

js生成随机数的方法
js生成随机数的方法

js生成随机数的方法有:1、使用random函数生成0-1之间的随机数;2、使用random函数和特定范围来生成随机整数;3、使用random函数和round函数生成0-99之间的随机整数;4、使用random函数和其他函数生成更复杂的随机数;5、使用random函数和其他函数生成范围内的随机小数;6、使用random函数和其他函数生成范围内的随机整数或小数。

2023.09.04

2108

4

如何启用JavaScript
如何启用JavaScript

JavaScript启用方法有内联脚本、内部脚本、外部脚本和异步加载。详细介绍:1、内联脚本是将JavaScript代码直接嵌入到HTML标签中;2、内部脚本是将JavaScript代码放置在HTML文件的`<script>`标签中;3、外部脚本是将JavaScript代码放置在一个独立的文件;4、外部脚本是将JavaScript代码放置在一个独立的文件。

2023.09.12

2370

6

Js中Symbol类详解
Js中Symbol类详解

javascript中的Symbol数据类型是一种基本数据类型,用于表示独一无二的值。Symbol的特点:1、独一无二,每个Symbol值都是唯一的,不会与其他任何值相等;2、不可变性,Symbol值一旦创建,就不能修改或者重新赋值;3、隐藏性,Symbol值不会被隐式转换为其他类型;4、无法枚举,Symbol值作为对象的属性名时,默认是不可枚举的。

2023.09.20

1499

5

java访问控制修饰符介绍
java访问控制修饰符介绍

java访问控制修饰符有四种,分别是public、protected、private、默认访问修饰符。详细介绍:1、public,public是最宽松的访问控制修饰符,被修饰的类、方法和变量可以被任何其他类访问,当一个类、方法或变量被声明为public时,它们可以在任何地方被访问,无论是同一个包中的类还是不同包中的类;2、protected修饰符等等。

2023.09.20

500

7

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 11.1万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.1万人学习