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

我的javascript函数有问题,无法使用回调函数

该函数获取“命令”列表,并对其进行迭代。它执行一个接一个的命令。 为了做到这一点,我必须使用带有回调的递归函数

这里有一个例子来描述它:

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