Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/469.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 高效的调用栈中断技术_Javascript_Callstack - Fatal编程技术网

Javascript 高效的调用栈中断技术

Javascript 高效的调用栈中断技术,javascript,callstack,Javascript,Callstack,场景 我有一个worker,它处理项目并通过处理函数调用传播结果 代码 在某些情况下,Worker会在processNextItem()调用和resultHandler()回调之间内部调用异步方法,从而重置调用堆栈: function Worker(resultHandler) { this.processNextItem = function () { // some work ... // propagate result

场景

我有一个worker,它处理项目并通过处理函数调用传播结果

代码

在某些情况下,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();
但这种情况并不经常发生,有时会出现未捕获的RangeError:由于递归调用,超出了最大调用堆栈大小:
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
    }
}

事实上,数据依赖于顺序。那个配料系统正是我现在解决它的方法。谢谢,但这看起来更像是一种变通方法。听起来很痛苦,这确实是一种变通方法,但我认为这可能是最快的方法,除非你能将序列重组为非顺序依赖的。我提出了一些想法,比如使用setInterval创建一个准堆栈线程,但我想它也会有同样的性能问题。或者,您可以根据需要的延迟通过服务器处理数据?我不确定非有序数据在这种情况下有何帮助。你能解释一下吗?我更感兴趣的是理解像这样的问题通常应该如何解决,因为它们在回调基础语言中应该很常见,而不是解决我当前的情况(因为它已经在工作)。在非有序的情况下,您可以在基本循环中启动每个进程调用,然后,如果某个进程需要某个数据段,则可以使用setTimeout()递归该调用,直到加载数据为止。显然,如果下一项依赖于上一项的完成,那么像这样的异步调用可能会在某种程度上破坏它。至于其他语言,JS由于缺乏多线程和休眠而受到一定程度的限制,因此我们必须使用诸如setTimeout()之类的混乱回调函数。