javascript - 高效的调用堆栈中断技术

标签 javascript callstack

场景

我有一个工作人员处理项目并通过处理程序函数调用传播结果。

代码

在某些时候,Worker 在 processNextItem() 调用和 resultHandler() 回调之间内部调用异步方法,这会重置调用堆栈:

function Worker(resultHandler) {
    this.processNextItem = function () {
        // some work
        ...

        // propagate result
        resultHandler(someResult);
    }
}   

var myResultHandler = function (result) {
    // Process result
    ...

    // Process next item
    worker.processNextItem();
};

var worker = new Worker(myResultHandler);

// Start working on first item
Worker.processNextItem();

但这种情况发生的频率不够高,有时我会得到 Uncaught RangeError: Maximum call stack size exceeded,因为递归调用: processNextItem() -> resultHandler() -> processNextItem() -> resultHandler() -> processNextItem() -> resultHandler() -> 等

为了打破它,我尝试使用 setTimeout:

this.processNextItem = function () {
    // some work
    ...

    // propagate result
    setTimeout(function () { resultHandler(someResult); }, 0);
}

但它会显着降低性能(我有数百个项目要处理)。

问题

有没有办法通过异步调用打破调用堆栈,但比setTimeout更有效?或者我应该手动计算同步调用并每 1000 次调用一次 setTimeout 还是什么?


我的解决方案:解决方法

最初我解决了这个问题,正如@nepeo 所写:创建一个同步回调计数器并使每 1000 个回调异步。这显然是解决方法,因为调用堆栈限制因浏览器而异(并且可能因平台和版本而异)。

最终我通过批处理结果解决了这个问题:

function Worker(resultHandler) {
    this.processNextBatch = function () {
        // some ASYNC work
        ...

        // propagate results
        resultsHandler(someResults);
    }
}   

var myResultsHandler = function (results) {
    results.forEach(function (result) {
        // Process result
        ...
    });

    // Process next item
    worker.processNextBatch();
};

var worker = new Worker(myResultsHandler);

// Start working on first item
Worker.processNextBatch();

但这并没有回复这个话题,我仍然想知道答案。

最佳答案

我假设此数据的处理是依赖于顺序的?如果不是,我会尝试对调用处理程序的进程函数进行非递归调用,这样会快得多,而且不会出现堆栈问题!如果您的批处理系统失败,可能是最不糟糕的解决方案。

function _batch(callback){
    this.counter = 0;
    this.callback = callback;
    this.count = function(){
        if(this.counter >= 1000){
            setTimeout(callback,0);
            this.counter = 0;
            return false;
        }
        else
            this.counter++
        return true;
    }
}

如果结果处理程序应该递归则返回 true。

或者潜在的重组?如果没有更多信息,很难知道这是否有效。

var position = 0;
function process()
{
    while(1)
    {
        if(!bDataReady){
        setTimeout(process,5);
        break;}
        //process data
        //propagate data
        position ++;
        if(bComplete)
            break
    }
}

关于javascript - 高效的调用堆栈中断技术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24776091/

相关文章:

javascript - 我可以让 dijit/form/FilteringSelect 不那么挑剔吗?

JavaScript(node.js) 存储 .then 中的(var) 信息

javascript - 用 javascript 构建原子设计开发生态系统

multithreading - 如何在 Visual Studio 中所有线程的调用堆栈中转储或搜索

windows - WinDbg 没有显示整个调用堆栈?

javascript - 仅在多个子组件运行完成后才更新父组件

javascript - 如何在React js api中以小数形式传递对象值

javascript - NodeJS 函数内某些代码的最大调用次数不超过

c++ - 如何解释此调用堆栈信息

java - JUnit 空指针异常