繁体   English   中英

JavaScript中的睡眠功能-不使用递归

[英]Sleep function in javascript - without using recursion

首先,我研究了周围所有的“睡眠”问题(例如,sleep()的JavaScript版本是什么? ),但没有找到可接受的解决方案。

我想为各种算法制作一个可视化的教育工具。 为了做到这一点,我在jQuery中使用javascript来显示数据并将其很好地绘制。 为了启动它,我想做一个排序示例,在其中显示一个数组,将其改组后再以视觉上令人愉悦的方式进行排序。 所以我想发生的是,两个单元格被突出显示(容易),可能被交换(容易),然后在测试下一个对(困难)之前有一个小的延迟。

我了解到javascript中没有明确的“睡眠”方法。 但是,将代码重组为使用setTimeout意味着将递归重写所有算法,这是一个巨大的障碍(尽管显然并非不可能)。

作为一个示例问题,请看一下气泡排序示例:

function bubble_sort(arr){
    for(var i=0;i<arr.length;i++){
        for(var j=1;j<arr.length;j++){
            highlight(j-1);
            highlight(j);
            if(arr[j-1] > arr[j]){
                visible_swap(arr, j, j-1);
            }
            sleep(1000);
        }
    }
    exhibit_array(arr);
}

显然,这可以递归地重写以与setTimeout一起使用,但是要对我所考虑的所有算法进行此操作都将花费大量时间。 我想念什么吗? 有没有一种“简便”的方法可以使实现保持现状并随意休眠?

编辑:我发现了两个解决方案:一个漂亮的和一个兼容的。 恐怕,漂亮的代码只能在firefox上使用,并利用了出色的yield语义(此处有一些示例说明: https : //developer.mozilla.org/en/New_in_JavaScript_1.7 )。 这实际上完美地解决了我的问题,因此:

function bubble_sort(arr){
    for(var i=0;i<arr.length;i++){
        for(var j=1;j<arr.length;j++){
            highlight(j-1);
            highlight(j);
            if(arr[j-1] > arr[j]){
                visible_swap(arr, j, j-1);
            }
            yield true;
        }
    }
    yield false;
}
var bubble = bubble_sort(arr)
function gen(){
    if(bubble.next()){
        setTimeout(gen, 500);
    }
    else{
        alert("Done!");
    }
}

这对我来说效果很好,但确实依赖于当前仅在firefox中支持的yield功能。 请注意,要使其完全起作用,您需要使用<script type =“ text / javascript; version = 1.7”>。 然而,这是完美的。 它也可能适用于无限算法,如果需要的话,显示它们徒劳无功。

根据以下答案,我发现的第二个解决方案也有效:

function bubble_sort(arr){
    var q = new Array();
    for(var i=0;i<arr.length;i++){
        for(var j=1;j<arr.length;j++){
            q[q.length] = [ [highlight, j-1 ], [highlight, j] ];
            if(arr[j-1] > arr[j]){
                swap(arr, j, j-1);
                q[q.length] = [ [visible_swap, j, j-1] ];
            }
        }
    }
    return q;
}
function play(q, step){
    if(q.length == 0)
        return;
    clear_highlights();
    cmds = q.shift();

    for(ind in cmds){
        cmd = cmds[ind];
        f = cmd.shift();
        f.apply(null, cmd);
    }
    setTimeout(function(){ play(q, step); }, step);
}

这也可以。 从语法上来说这很麻烦,但是绝对可以在所有浏览器上正常工作。

尽管如此,似乎所有的javascript“扩展”都实现了类似于睡眠的语法,这显然比上述所有方法都要好。 谢谢您的帮助!

最近,我对次回文查找器算法进行了可视化处理,它使用了setTimeout,并且不需要以递归形式重写算法。

请参阅此示例

一般原则是为气泡排序建立一堆命令,这将是一串高亮和交换命令。 然后,您可以使函数每N毫秒运行一次,该函数从堆栈中获取命令并将其可视化。

commands = [
    ['highlight', 1, 5]
    ['swap', 1, 5]
    ['highlight', 3, 7]
    ...
];

setInterval(function() {
    var cmd = commands.shift();
    visualize(cmd);
}, 1300);

在我的问题中,finder算法是用Python编写的,由用户提供,我无法对其进行修改。 幸运的是,Python允许重载访问和比较运算符,并记录算法执行的每个动作。 RecString类 在JavaScript中,您不能这样做,但这对您来说不是问题,因为您可以修改原始算法。

我可以通过电子邮件将JS来源通过电子邮件发送给您,它是匆忙编写的,但仍然很有用。

另一个想法-StratifiedJS 这是一个简单的jsFiddle示例

<script src="http://code.onilabs.com/apollo/0.13/oni-apollo.js"></script>
<script type="text/sjs">
  for (var i = 1; i < 4; i++) {
      alert(i);
      hold(1000);
  }
</script>

我将使用setTimeout ,我相信这是您在客户端上最接近“睡眠”状态的方法。

这个答案不能解决一般情况,但是也许您可以增加每条指令的间隔,以使它们彼此之间每秒运行一秒钟。

function bubble_sort(arr){
    var interval = 0;  // increases with each loop
    for(var i=0;i<arr.length;i++){
        for(var j=1;j<arr.length;j++){
            (function(i, j) {
                setTimeout(function() {
                    highlight(j-1);
                    highlight(j);
                    if(arr[j-1] > arr[j]){
                        visible_swap(arr, j, j-1);
                    }
                }, interval);
            })(i, j);
            interval += 1000;
        }
    }
    exhibit_array(arr);
}

因此,第一个操作一次运行,第二个运行在一秒钟后运行,第三个运行总计两秒钟后,依此类推。

该解决方案提供了最小化代码重写的优势:只需将循环内容包装在setTimeout (该包装与循环变量一起包装在闭包中),并在每次循环迭代后添加一行以增加interval

使用setTimeout()不是递归的。

您可以使用闭包来跟踪状态。 但是,必须将此for循环更改为while才能起作用:

function bubbleSort(arr) {
  (function(i, j) { // <- this closes over i and j
    function nextSortStep() {
      while (i < arr.length) {
        while (j < arr.length) {
          highlight(j - 1);
          highlight(j);
          if (arr[j - 1] > arr[j]) {
            visibleSwap(arr, j, j - 1);
          }
          j++;
          return setTimeout(nextSortStep, 1000);
        }
        i++;
        j = 1;
        return setTimeout(nextSortStep, 1000);
      }
      exhibitArray(arr);
    }
    nextSortStep();
  })(0, 1); // <- loop initialization
}

camelCase ,JavaScript不是PHP,函数名称通常在camelCase

按照Lebedev的想法,我将存储“数组排序的演变”,然后使用setInterval()进行显示。 http://jsfiddle.net/mari/EaYRZ/

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM