高效的调用栈中断技术

时间:2014-07-16 08:40:50

标签: 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:超出最大调用堆栈大小,因为递归调用: processNextItem() -> resultHandler() -> processNextItem() -> resultHandler() -> processNextItem() -> resultHandler() -> etc

为了打破它,我尝试使用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();

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

1 个答案:

答案 0 :(得分:0)

我假设这些数据的处理依赖于顺序?如果不是,我会尝试调用处理程序的进程函数的非递归调用,它会更快,你不会有堆栈问题!如果你的批处理系统失败可能是最糟糕的修复方法。

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
    }
}