Javascript 忙等待替代方案
我的javascript函数有问题,无法使用回调函数 该函数获取“命令”列表,并对其进行迭代。它执行一个接一个的命令。 为了做到这一点,我必须使用带有回调的递归函数 这里有一个例子来描述它:Javascript 忙等待替代方案,javascript,recursion,callstack,busy-waiting,Javascript,Recursion,Callstack,Busy Waiting,我的javascript函数有问题,无法使用回调函数 该函数获取“命令”列表,并对其进行迭代。它执行一个接一个的命令。 为了做到这一点,我必须使用带有回调的递归函数 这里有一个例子来描述它: function processList( inputArray, cb ){ if(inputArray.length == 0) return cb(); //No commands left var command = inputArray.pop(); //Ge
function processList( inputArray, cb ){
if(inputArray.length == 0) return cb(); //No commands left
var command = inputArray.pop(); //Get last Element from the List
processCommand(command, function(){ //Execute the command
return processList(inputArray, cb); //Continue with the next command, when this one finished
});
}
function processCommand(command, cb){
setTimeout(function(){
console.log("Processed command "+command);
cb();
}, 10);
}
这就是我调用函数的方式:
processList( ["cmd1", "cmd2", "cmd3"], function(){
console.log("DONE");
});
它工作得很好,一个命令在前一个命令之后执行
我的问题:
function processList( inputArray, cb ){
if(inputArray.length == 0) return cb(); //No commands left
var command = inputArray.pop(); //Get last Element from the List
processCommand(command, function(){ //Execute the command
return processList(inputArray, cb); //Continue with the next command, when this one finished
});
}
function processCommand(command, cb){
setTimeout(function(){
console.log("Processed command "+command);
cb();
}, 10);
}
该列表包含数千个元素,甚至可能在处理过程中该列表获得新命令。我在几秒钟内达到最大调用堆栈
我不需要调用堆栈。当我完成最后一个命令时,只有数千个返回,这些返回引导我回到函数,函数启动了一切
我不知道如何解决这个问题,我不想使用繁忙等待(这使得代码效率极低)
还有别的把戏吗?比如信号或者破坏调用堆栈
编辑:
function processList( inputArray, cb ){
if(inputArray.length == 0) return cb(); //No commands left
var command = inputArray.pop(); //Get last Element from the List
processCommand(command, function(){ //Execute the command
return processList(inputArray, cb); //Continue with the next command, when this one finished
});
}
function processCommand(command, cb){
setTimeout(function(){
console.log("Processed command "+command);
cb();
}, 10);
}
下面是一个用于演示的JSFIDLE:
(请注意,您的浏览器选项卡可能会冻结/崩溃)
错误消息是uncaughtrangeerror:超过了最大调用堆栈大小
我用Chrome进行了测试,您可能需要在其他浏览器中增加数组(即有一个巨大的调用堆栈)
Edit2:
function processList( inputArray, cb ){
if(inputArray.length == 0) return cb(); //No commands left
var command = inputArray.pop(); //Get last Element from the List
processCommand(command, function(){ //Execute the command
return processList(inputArray, cb); //Continue with the next command, when this one finished
});
}
function processCommand(command, cb){
setTimeout(function(){
console.log("Processed command "+command);
cb();
}, 10);
}
感谢您的帮助,我没有意识到添加/删除超时之间的区别。停下来,这解决不了我的问题。
以下是一些更详细的信息:
我有不同的命令。有些命令是同步的,有些是异步的。所以我不得不使用回调函数,但调用堆栈仍然存在问题
下面是一个更新的示例:
var commands = [];
for(var i=15000; i>=0;i--){ commands.push(i); }
processList(commands, function(){
alert("DONE");
});
function processList( inputArray, cb ){
if(inputArray.length == 0) return cb(); //No commands left
var command = inputArray.pop(); //Get last Element from the List
processCommand(command, function(){ //Execute the command
return processList(inputArray, cb); //Continue with the next command, when this one finished
});
}
function processCommand(command, cb){
if(command%2 == 0){ //This command is synchron
console.log("Processed sync. command "+command);
cb();
}else{
setTimeout(function(){
console.log("Processed async. command "+command);
cb();
}, 1);
}
}
还有fiddle:我认为这样的东西可能不会保留在调用堆栈上,因为它不会将回调作为参数提供
function processList( inputArray, cb ){
var processCommand = function(){
if(inputArray.length == 0) cb(); //No commands left
var command = inputArray.pop();
setTimeout(function(){
console.log("Processed command "+command);
processCommand();
}, 10);
};
processCommand();
}
这就是原因。如果没有setTimeout
,您将很容易达到调用堆栈限制():
您可以看到,无论您处理了多少命令(),当记录“DONE”时,堆栈总是这样:
console.log()上的断点
readyHandler show/:8
进程列表显示/:13
完成命令显示/:17
稍后节目/:24
//设置超时
听起来是一个完美的例子。tbh我还没有试过,但它们在我的名单上排在首位。 放松一下。此外,承诺中的操作是否同步也无关紧要 所以你会有
commands.forEach(function(cmd) {
execCmd(cmd).then(onSuccess, onFailure);
});
很抱歉,这不是很具体,但您必须做更多的研究。我可以用10000个元素运行
processList
,而不会遇到任何问题。我想到的是async,async.queue我无法检测到严重的问题。您能否向我们展示stackoverflow错误的堆栈跟踪,以确定哪些函数导致了问题?您确定processCommand
始终是异步的吗?@Bergi它将调用processCommand()一次,从那时起,当处理完成时,将从超时函数调用processCommand(),因此它将等待。嗯,我知道,您已将processCommand
直接合并到processList
中。我不认为这是OP想要的。你可能是对的,但我认为这可能会帮助OP。让他来决定:)我创造了一个小提琴:但不幸的是,你的建议并不能解决问题。我仍然达到了最大调用堆栈大小,因为浏览器会记住返回地址。@Bergi:解决方案有多难看并不重要,只要它一个接一个地执行命令,并且不受调用堆栈的限制。谢谢,我没有意识到这一点。但是,我不能使用该解决方案,因为我有一个同步和异步命令的组合(请参阅我更新的问题)。如果您可以提供一个工作示例,我将排除您的答案:)使每秒钟的命令同步仍然应该工作-达到的堆栈大小将增加一倍,但仍然是常量。如果不可预测,您可以通过将setTimeout(cb,1)
而不是cb()
放在同步部分,使每个处理异步,或者您可以将几个在循环中运行的同步命令“分块”在一起,然后调用(异步)回调。谢谢。在最坏的情况下,我将只使用同步函数(在这种情况下,我达到了堆栈限制),但使用循环和回调的组合实际上应该是可行的。
commands.forEach(function(cmd) {
execCmd(cmd).then(onSuccess, onFailure);
});