javascript - 忙等待替代方案

标签 javascript recursion callstack busy-waiting

我的 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");
});

它工作得很好,一个命令在前一个命令之后执行。

我的问题:

列表包含数千个元素,列表甚至有可能在处理过程中获取新命令。我在几秒钟内就达到了最大调用堆栈。

我不需要调用堆栈。当我完成最后一个命令时,只有数千个返回,它们引导我回到启动一切的函数。

我不知道如何解决这个问题,而且我不想使用忙等待(这使得代码效率极低)。

还有别的技巧吗?喜欢信号还是破坏调用堆栈?

编辑:

这里有一个jsFiddle用于演示:http://jsfiddle.net/db6J8/ (请注意,您的浏览器选项卡可能会卡住/崩溃)

错误消息是Uncaught RangeError:超出最大调用堆栈大小

我用Chrome测试过,在其他浏览器中你可能需要增加数组(IE有一个巨大的Callstack)。

编辑2:

感谢您的帮助,我不知道添加/删除超时之间的区别。悬停,它不能解决我的问题。 以下是更多详细信息: 我有不同的命令。有些命令是同步的,有些命令是异步的。所以我必须使用回调函数,但调用堆栈仍然存在问题。

这是一个更新的示例:

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 :http://jsfiddle.net/B7APC/

最佳答案

// setTimeout(function(){
    console.log("Processed command " + command);
    cb();
// }, 1);

就是这个原因。如果没有 setTimeout,您很容易就会达到调用堆栈限制 ( Demo with named functions ):

Maximum recursion depth exceeded:
finishedCommand _display/:16
processCommand _display/:23
processList _display/:15
finishedCommand _display/:16
processCommand _display/:23
…
processList _display/:15
finishedCommand _display/:16
processCommand _display/:23
processList _display/:15
<Global Scope> _display/:16

选择同步循环而不是递归调用processCommand

如果将 setTimeout 重新生效,每个计时器事件都会使用全新的调用堆栈调用该函数,并且永远不会溢出:

setTimeout(function later(){
    console.log("Processed command " + command);
    cb();
}, 1);

您会看到,当记录“DONE”时,堆栈始终如下所示 - 无论您处理了多少命令 ( Demo ):

BreakPoint at console.log()
readyHandler show/:8
processList show/:13
finishedCommand show/:17
later show/:24
<Global Scope> // setTimeout

关于javascript - 忙等待替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22199995/

相关文章:

用于递归计算ln(n!)的java方法

javascript - 如何在大屏幕尺寸上显示手机屏幕设计?

javascript 和 Facebook 登录 API : get the user's email

javascript - 使用应用程序级别解析 AngularJS 的动态指令模板

python - 如何在多层嵌套列表的中间插入?

java - 递归将 N 项乘以 2(二进制序列)

c++ - 在 C++ 中动态创建函数调用

javascript - .defineProperty 方法期间调用堆栈和 this 的行为

JavaScript 更改控制台调用堆栈

javascript - 即使填充设置为 'rgba(0,0,0,0)' ,为什么最近绘制的弧线填充为黑色?