在JavaScript中等待包装setTimeout中的所有内容

时间:2014-04-07 22:22:46

标签: javascript jquery settimeout

所以,我正在创建一个机器人来在线玩视频游戏(完全合法,那里有一个用于机器人竞赛的服务器,不用担心)。代码是用JavaScript编写的,我现在只是采用它,而且我无法告诉机器人做某事,然后等待时间或条件,直到做其他事情。

到目前为止,我只是简单地将所有内容包装在巨大的setTimeout命令中,但这非常不优雅。

没有太多与发布相关的代码,但基本上我已经编写了很多代码,可以移动到特定位置,制动,追逐其他玩家,大多数使用递归setTimeout命令 - 按某些按钮,重置变量,然后如果条件不满足则再次启动该功能。如果我想移动到一个特定的位置然后在我完成时刹车,通常我会把代码放在这样:

moveTarget(target);
brake();
[...Execute rest of code...]

然而,JavaScript同时执行这两个命令,这显然不能很好地工作。有没有办法制作更像这样的东西(或等效的条件而不是指定的时间):

moveTarget(target);
wait3Seconds();
brake();
[...Execute rest of code...]

无需执行此操作:

moveTarget(target);
setTimeout(function(){
    brake();
    [...Execute rest of code...]
},3000);

鉴于我将会遇到多少这样的情况,我的代码最终会看起来像一个巨大的嵌套setTimeouts混乱,这不是很漂亮。有没有更好的办法?我已经在使用JQuery,所以我非常愿意在必要时使用它。

3 个答案:

答案 0 :(得分:4)

没有更好的方法可以做到这一点。原因是任何类型的等待都将触发进入任务队列的任务。由于javascript是单线程的,因此它必须使用这些任务队列,因此如果存在指令,它将继续执行超过setTimeout的指令。

为了在延迟后执行代码,它必须在超时回调中,否则它将立即执行。

答案 1 :(得分:4)

一点背景......

JavaScript不会像您可能习惯的其他编程语言一样处理并发。相反,JavaScript只有一个主线程,而是有一个队列用于注册,然后按顺序处理事件。

由于这个原因,不要做很长时间阻塞线程的事情非常重要(比如Thread.sleep()这样的函数会这样做)。这就是为什么你应该使用setTimeout或setInterval来做这样的事情。

您始终可以创建自定义睡眠功能,以便以您请求的样式编写代码。这可能是这样的:

function sleep(millis) {
  var startTime = Date.now();
  while (Date.now() < startTime + millis) {}
}

但这将是非常,非常糟糕。这会在此睡眠功能运行时冻结页面。

回到你的问题......

你基本上需要重构你的代码,以便更多&#34; eventful&#34;。您应该编写JavaScript代码以使用回调和超时,而不是在同一个块中包含大的线性代码块。

因此,您展示的最后一个代码块实际上是您应该使用JavaScript的范例:

moveTarget(target);
setTimeout(function(){
  brake();
  [...Execute rest of code...]
},3000);

然而,你当然可以清理很多东西,如果不是[...Execute rest of code...],你将它拆分成其他函数并从你的setTimeout回调中调用它们。当然,在任何编程语言中保持代码块小而简洁是一个很好的经验法则。


您可能还有兴趣查看request animation frame function

答案 2 :(得分:1)

如果您在具有wait命令的链中创建了所有方法,则可以执行此操作,类似于jQuery队列系统。

$("<div>").queue(function(next){
    // do a
    a();
    next();
}).delay(3*1000).queue(function(next){
    // after 3 seconds do b
    b();
    next();
}).delay(3*1000).queue(function(next){
    // after 3 more seconds do c
    c();
    next();
}).dequeue(); //.dequeue() starts it, only has to be called to make a queue that isn't currently running begin.

所以你所要做的就是保持相同的链并继续添加它。