【问题标题】:JavaScript - Can't seem to 'reset' array passed to a functionJavaScript - 似乎无法“重置”传递给函数的数组
【发布时间】:2016-04-23 01:57:37
【问题描述】:

我对 JavaScript 有点陌生,但我对一般编程有相当的经验。我怀疑我的问题可能与范围界定或将数组作为参数传递的细节有关,但我不确定。

高级目标是使用多个“节点”进行实时绘图,每个节点每秒生成 50 个点。我已经让这个工作直接运行到一个数组中,并由 dygraphs 和 C3.js 渲染,并很快意识到这是太多的数据,无法持续实时渲染。 Dygraphs 似乎在大约 30 秒后开始影响用户体验,而 C3.js 似乎在大约 10 秒后窒息。

下一个尝试是根据缩放级别抽取绘制的数据。

我将数据保存到一个“对象”中,我使用的对象有点像其他语言的字典。使用 AJAX 请求进展顺利。思路是利用AJAX请求创建一个大的数据缓冲区,并使用keys来存储单元根据序列号生成的数据作为keys。这运行良好,并且正在按预期填充对象。我觉得在我提出问题之前了解这个对象的“结构”是有益的。如下:

{
    1: [[x10,y10], [x11,y11], [...], [x1n, y1n]],
    2: [[x20,y20], [x21,y21], [...], [x2n, y2n]],
    ... : [ ... ]
    a: [[xa0,ya0], [xa1,ya1], [...], [xan, yan]]
}

定期地,该数据的一个子集将用于生成 dygraphs 图。我正在抽取存储的数据并创建一个“绘图缓冲区”来保存实际数据的子集。

dygraphs 库以多种方式获取数据,但我想“本地”构造它,它只是一个数组数组。数组中的每个数组都是数据的“行”。所有行必须具有相同数量的元素才能排列成列。生成的数据可能同时也可能不同。如果数据 x 值完全匹配,则结果数据将如下所示,仅针对两个节点,因为 x10 = x20 = xn0:

[
    [x10, y10, y20],
    [x11, y11, y21],
    [ ... ],
    [xan, yan, yan]
]

请注意,这只是行中的 x 和 y。实际上,每个序列号的时间可能不对齐,因此可能更接近:

[
    [x10, y10, null],
    [x20, null, y20],
    [x11, y11, y21],
    [ ... ],
    [xan, yan, yan]
]

对不起所有的背景。我们可以找到我遇到问题的代码。我定期尝试使用以下代码创建绘图缓冲区:

window.intervalId = setInterval(
    function(){
        var plotData = formatData(nodeData, 45000, 49000, 200);

        /* dygraphs stuff here */
    },
    500
);

function formatData(dataObject, start, end, stride){
    var smallBuffer = [];

    var keys = Object.keys(dataObject);
    keys.forEach(
        function(key){
            console.log('key: ', key);

            mergeArrays(dataObject[key], smallBuffer, start, end, stride);
        }
    );

    return smallBuffer;
}

function mergeArrays(sourceData2D, destDataXD, startInMs, endInMs, strideInMs){
    /* ensure that the source data isn't undefined */
    if(sourceData2D){
        /* if the destDataXD is empty, then basically copy the 
         *  sourceData2D into it as-is taking the stride into account */
        if(destDataXD.length == 0){
            /* does sourceData2D have a starting point in the time range? */
            var startIndexSource = indexNear2D(sourceData2D, startInMs);
            var lastTimeInMs = sourceData2D[startIndexSource][0];

            for(var i=startIndexSource; i < sourceData2D.length; i++){
                /* start to populate the destDataXD based on the stride */
                if(sourceData2D[i][0] >= (lastTimeInMs + strideInMs)){
                    destDataXD.push(sourceData2D[i]);
                    lastTimeInMs = sourceData2D[i][0];
                }

                /* when the source data is beyond the time, then break the loop */
                if(sourceData2D[i][0] > endInMs){
                    break;
                }
            }
        }else{
            /* the destDataXD already has data in it, so this needs to use that data
             *  as a starting point to merge the new data into the destination array */
            var finalColumnCount = destDataXD[0].length + 1;
            console.log('final column count: ', finalColumnCount);

            /* add the next column to each existing row as 'null' */
            destDataXD.forEach(
                function(element){
                    element.push(null);
                }
            );

            /* TODO: move data into destDataXD from sourceData2D */

        }
    }
}

添加一些信息,因为它可能不费吹灰之力就不言自明了。我创建了两个函数,“formatData”和“mergeArrays”。这些可以在一个函数中完成,但我更容易从概念上分离出“对象”域和“数组”域。 “formatData”函数简单地遍历存储在每个键中的所有数据,每次调用“mergeArray”例程。 “mergeArray”例程尚未完成,这是我遇到问题的地方。

第一次,fo​​rmatData 应该创建一个空数组 - smallBuffer - 使用 mergeArrays 将数据合并到该数组中。第一次执行 'mergeArrays' 我看到 smallBuffer 确实正在创建并且是一个空数组。这个空数组作为参数提供给 'mergeArrays' 并且 - 第一次通过 - 这非常有效。下一次,“smallBuffer”数组不再为空,因此“mergeArrays”中的第二种情况被执行。我的第一步是计算列数,以便我可以适当地填充每一行。这工作正常,但有助于指出问题。下一步是简单地将空列的“null”值附加到每一行。这就是事情变得奇怪的地方。第一次通过“mergeData”后,destDataXD 仍包含来自先前执行的“空”数据。从本质上讲,'var smallBuffer = [];'实际上并没有清除并保留一些东西。直到接近尾声,这件事才明显。我无法准确解释 b/c 发生了什么我不完全理解,但 destDataXD 在最后不断增长“空值”,而没有按预期正确重置。

感谢您的宝贵时间,我期待听到您的想法,j

【问题讨论】:

  • 创建一个有效的 sn-p(带有一些固定数据)来演示该问题会很有用,因为您的 sn-p 失败了,因为nodeData 不存在。
  • 好主意。我应该包括 nodeData。感谢您花时间浏览和评论。

标签: javascript arrays parameters scope


【解决方案1】:

快速通读代码,我看到的危险点是你先给destDataXD添加一个元素。

destDataXD.push(sourceData2D[i]);

请注意,您不是在推送数组的副本。您正在添加对该数组的引用。 destDataXDsourceData2D 现在共享相同的数据。

当然,当您将任何null 值推送到destDataXD 中的数组时,您也在修改sourceData2D

你应该使用javascript数组复制方法slice

destDataXD.push(sourceData2D[i].slice());

【讨论】:

  • 这就是答案,非常感谢!我已经阅读并在此处不可见的其他代码部分实现了相同类型的解决方案,但我没有看到它。再次感谢您,我花了 6 个多小时才找到它!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 2011-06-20
  • 1970-01-01
  • 2012-03-14
  • 2021-11-13
相关资源
最近更新 更多