首先,我已经看过周围的所有“睡眠”问题(例如What is the JavaScript version of sleep()?),但我找不到可接受的解决方案。
我想为各种算法制作视觉教育工具。为了做到这一点,我正在使用带有jQuery的javascript来显示数据并很好地绘制它。为了启动它,我想做一个排序示例,其中一个数组被显示,洗牌,然后以一种视觉上令人愉悦的方式排序。所以我想要发生的是两个单元格突出显示(简单),可能交换(简单),然后在测试下一对(硬)之前有一个小延迟。
我知道javascript中没有明确的'sleep'方法。但是,使用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功能。请注意,要使其完全正常工作,您需要使用&lt; script type =“text / javascript; version = 1.7”&gt;。然而,这是完美的。它本来可以用于无限的算法,如果需要的话,显示它们徒劳无功。
我找到的第二个解决方案也可以,基于以下答案:
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'扩展'实现类似睡眠的语法,这显然比上述所有更好。 谢谢你的帮助!
答案 0 :(得分:6)
最近我对sub-palindrome finder算法进行了可视化,它使用了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 class。在JavaScript中你不能这样做,但在你的情况下这不是问题,因为你可以修改原始算法。
如果你愿意,我可以通过电子邮件向你发送JS源代码,它是用急速编写的,但无论如何都可能有用。
答案 1 :(得分:2)
另一个想法 - StratifiedJS。这是一个简单的jsFiddle example:
<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>
答案 2 :(得分:1)
我会与setTimeout
合作,我相信这是你最接近客户端的“睡眠”等价物。
答案 3 :(得分:1)
这个答案并不能解决一般情况,但也许你可以增加每条指令的间隔,使它们相继运行一秒钟。
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
循环迭代。
答案 4 :(得分:0)
使用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
}
另外,JavaScript不是PHP,函数名称通常在camelCase
。
答案 5 :(得分:0)
遵循Lebedev的想法,我将存储“数组排序的演变”,然后使用setInterval()来显示它们。 http://jsfiddle.net/mari/EaYRZ/