非递归函数的最大调用堆栈

时间:2019-08-12 19:29:02

标签: javascript

您好,我正在处理此函数的问题,导致最大调用堆栈超出错误。该函数不是递归的,所以我真的不明白为什么它超出了调用堆栈。

我从某个博客(可能是stackoveflow)复制了此函数,它将一个字数组转换为字节数组,以便在pako.js中使用。

它用于为zlib压缩字符串充气。

当字符串较小时,它不会超出调用堆栈,但是对于较长的字符串,它将超过它。

我尝试用setTimeout重写它,但是它变得非常慢。 你们有什么建议吗?

谢谢。

const wordToByteArray = function (word, length) {
    let ba = [];
    let i;
    let xFF = 0xFF;

    if (length > 0)
        ba.push(word >>> 24);
    if (length > 1)
        ba.push((word >>> 16) & xFF);
    if (length > 2)
        ba.push((word >>> 8) & xFF);
    if (length > 3)
        ba.push(word & xFF);

    return ba;
};

const wordArrayToByteArray = function(wordArray, length) {
    if (wordArray.hasOwnProperty("sigBytes") && wordArray.hasOwnProperty("words")) {
        length = wordArray.sigBytes;
        wordArray = wordArray.words;
    }

    let result = [];
    let bytes;
    let i = 0;

    while (length > 0) {
        bytes = wordToByteArray(wordArray[i], Math.min(4, length));
        length -= bytes.length;
        result.push(bytes);
        i++;
    }

    return [].concat.apply([], result);
};

解决方案 谢谢您的回答,这就是解决方案。

    ...
    while (length > 0) {
        bytes = wordToByteArray(wordArray[i], Math.min(4, length));
        length -= bytes.length;
        bytes.forEach(function (byte) {
            result.push(byte);
        });
        i++;
    }

    return result;
};

2 个答案:

答案 0 :(得分:3)

[].concat.apply([], result);可能是您的问题;这实际上是在说“请致电[].concat(result[0], result[1], result[2], ..., result[result.length - 1])。对于较大的输入,您可能会按比例分配较大的resultPer MDN's warnings on apply

  

但是要注意:以这种方式使用apply时,您将冒超出JavaScript引擎的参数长度限制的风险。应用带有过多参数(想想成千上万个参数)的函数的结果因引擎而异(JavaScriptCore已硬编码argument limit of 65536),因为该限制(甚至包括任何过大的参数的性质,堆栈行为)未指定。一些引擎将引发异常。更有害的是,其他人将任意地限制实际传递给应用函数的参数数量。为了说明这后一种情况:如果这样的引擎有四个参数的限制(实际的限制当然要高得多),则示例中的参数5, 6, 2, 3会传递给apply而不是整个数组。

如果您的result数组确实很大,尝试将成千上万(或更多)个参数传递给Array.concat可能会炸毁您的堆栈。 MDN文档建议,在像您这样的场景中,您可以使用混合策略来避免栈被炸毁,无论大小如何,一次apply一次处理一大堆参数,而不是所有参数。

幸运的是,someone has already provided a guide on how to do this safely;只需使用它,并与extend中的每个子数组显式循环到result

答案 1 :(得分:0)

您的result数组非常大。这里的问题出在apply方法中,其中您提供了result作为参数。函数的参数被压入堆栈,这会导致堆栈溢出。