【问题标题】:Will Recursively Calling Web Service in JavaScript Cause StackOverflow在 JavaScript 中递归调用 Web 服务会导致 StackOverflow
【发布时间】:2016-10-14 07:15:58
【问题描述】:

我的迁移过程可能需要 2 到 3 天才能完成。我担心以下实现可能会由于它的递归方面而引发 StackOverFlow 异常。 JavaScript 是否真的构建了一个巨大的堆栈来执行这段代码?如果是这样,什么是更好的实施方式?我可能会调用此服务大约 1000 万次。

function mainFunc() {
        var url = getMyUrl();
        $.ajax({
            url: url,
            type: "POST",
            contentType: "application/json;charset=utf-8",
            dataType: "json",
            success: function (remaining) {
                if(remaining > 0) {
                   mainFunc();
                }
                else {
                    alert('done');
                }
            },
            error: function (x, e) {
                alert('error!');
            }
        });
    }

【问题讨论】:

    标签: javascript ajax web-services recursion asp.net-web-api


    【解决方案1】:

    首先,这听起来绝对不是应该从浏览器完成的事情,而是在服务器端处理。

    话虽如此,您的递归是异步发生的,因此肯定不会发生堆栈溢出。
    根据您的确切代码(更具体地说,闭包中包含哪些值),这可能会开始堆积内存。您还将使用额外的内存,因为每次调用 mainFunc 时都会重新创建成功和错误函数。

    您可以通过在mainFunc 外部声明这些函数,然后在mainFunc 函数内部传递对它们的引用来相当容易地解决此函数内存分配问题。

    这样做并不能完全免除您防止内存异常偏离路线的责任。这实际上取决于实际代码以及您在每次迭代中保留的引用。

    为了确定您的代码在这个漫长的过程中是否挂在资源上,您必须阅读代码并找出代码“泄漏”的位置,或者深入研究内存分析选项:

    https://developer.chrome.com/devtools/docs/javascript-memory-profiling

    排除闭包的示例:

    function mainFuncSuccess(remaining) {
        if(remaining > 0) {
           mainFunc();
        }
        else {
            alert('done');
        }
    }
    
    
    function mainFuncError() {
        alert('error!');
    }
    
    function mainFunc() {
            var url = getMyUrl();
            $.ajax({
                url: url,
                type: "POST",
                contentType: "application/json;charset=utf-8",
                dataType: "json",
                success: mainFuncSuccess,
                error: mainFuncError
            });
        }
    

    【讨论】:

    • 像这样在外面声明函数? success: callSuccess(remaining); 其中callSuccess 调用mainFunc()
    • 您知道我是否可以将remaining 作为参数放入mainFuncSuccess 中? remaining 现在未定义。
    【解决方案2】:

    因为$.ajax是异步的,所以直到远程服务器响应后才会调用success函数。换句话说,在每次迭代之后,JS 引擎基本上会“休眠”直到它得到响应,然后使用success 函数恢复。所以这在技术上不是递归的例子。无论需要多少次迭代,堆栈都应该保持相当小(假设没有您在此处未显示的其他因素对堆栈有贡献)。

    【讨论】:

      【解决方案3】:

      不,因为您没有在 mainFunc 中存储任何需要稍后使用的内容。没有任何对象需要存储在函数的范围内。

      在 chrome 中,您可以使用 window.performance.memory 来检查内存

      【讨论】:

      • 你不需要在函数之外存储任何东西来获得堆栈溢出(尝试(function foo(){ foo(); })())。
      • 这是一个简化的例子,这完全取决于他的代码究竟会是什么样子。
      猜你喜欢
      • 2017-09-13
      • 1970-01-01
      • 2013-12-13
      • 1970-01-01
      • 2011-04-01
      • 2014-10-31
      • 2020-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多