方案
我有一个工作人员处理项目并通过处理程序函数调用传播结果。
代码
在某些时候,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();
但这并没有回复这个帖子,我仍然想知道答案。
答案 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
}
}