如何在javascript中添加睡眠和等待逻辑

时间:2015-05-31 01:10:16

标签: javascript canvas settimeout sleep

我们正致力于可视化排序算法,需要添加睡眠和等待逻辑,以帮助可视化所选元素及其所比较的元素。在搜索了一下之后,我们找到了一个代码" function sleep(毫秒){...}"哪个应该按预期工作但到目前为止失败了。

在函数insertionSort(){...}中,当前元素用红色表示,与之比较的元素用蓝色表示,一旦当前元素与另一个元素交换颜色为蓝色。元素再次从蓝色变为白色(正常工作,使用调试器验证),但在执行期间,这些颜色转换不可见(每次迭代后只显示红色元素)



var element = function(value, color)
{
  this.value = value;
  this.color = color;
};

var x = [];
x[0] = new element(2, "white");
x[1] = new element(1, "white");
x[2] = new element(5, "white");
x[3] = new element(4, "white");
x[4] = new element(3, "white");
x[5] = new element(7, "white");
x[6] = new element(6, "white");
x[7] = new element(8, "white");
x[8] = new element(10, "white");
x[9] = new element(9, "white"); 


var i = 1;
var context;
var delayTime = 1000;

function myFunction()
{
  	var bar = document.getElementById("bar");
  	width = bar.width;
 	height = bar.height;
  	context = bar.getContext("2d");
 	window.setInterval(insertionSort, 3000);
}

function insertionSort()
{
    if(i>=0 && i<x.length)
    {
      	
		var j = i;
		x[j].color = "red";
		drawGraph(j);
		while(j>0 && x[j-1].value > x[j].value)
		{
		  
		  	x[j-1].color = "blue";
		 	x[j].color = "red";
			drawGraph();
			//need to add delay here
			sleep(delayTime);
			//swap
			var temp = x[j];
			x[j] = x[j-1];
			x[j-1] =  temp;
			drawGraph();
			// and here...
			sleep(delayTime);
			
			x[j].color = "white";
			drawGraph();
			
			j = j-1;
		}
		x[j].color = "white";
		i++;
  	}
  	else if(i>=x.length)
  	{
  	  	for(k=0;k<x.length;k++)
  	  	{
		    x[k].color = "white";
	    }
      	drawGraph();
      	i=-1;
  	}
}

function sleep(milliseconds) 
{
  	var start = new Date().getTime();
 	for (var i = 0; i < 1e7; i++) 
 	{
    	if ((new Date().getTime() - start) > milliseconds)
    	{
      		break;
    	}
  	}
}

function drawGraph()
{	
	context.StrokeStyle = "black";
	context.clearRect ( 0 , 0 , width, height);
    for(k=0;k<x.length;k++)
    {    
		context.fillStyle = x[k].color;
		//x and y coordinate of top left corner of rectangle
	    context.strokeRect(400+k*20, 18, 20, x[k].value*10);
	    context.fillRect(400+k*20, 18, 20, x[k].value*10);
	      
    }
}
&#13;
<html>
<head>
  <script language="javascript" type="text/javascript" src="../p5.js"></script>
  <!-- uncomment lines below to include extra p5 libraries -->
	<!--<script language="javascript" src="../addons/p5.dom.js"></script>-->
  <!--<script language="javascript" src="../addons/p5.sound.js"></script>-->
  <script language="javascript" type="text/javascript" src="sketch.js"></script>
  <!-- this line removes any default padding and style. you might only need one of these values set. -->
  <style> body {padding: 0; margin: 0;} </style>
</head>

<body>
  
  <button onclick="myFunction()">Try it</button>
  <canvas id="bar" width="1000" height="400" style="border:2px"></canvas>
  
</body>
</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

用于执行sleep()的方法在任何编程语言中都会很糟糕,因为它在等待时会消耗大量的CPU。然而,在JavaScript中,它特别糟糕,因为需要JavaScript程序来经常放弃控制;不允许长时间保持计算。例如,在Chrome浏览器中,Chrome会认为该程序没有响应,并会向用户建议他们将其删除。

但即使不是这样,它也不会产生预期的效果,我认为这是一些动画在屏幕上发生,从一步到另一步有一些延迟。 JavaScript在浏览器中的工作方式是,当您的程序放弃控制时,您对页面所做的任何更改都会被呈现;任何JavaScript代码运行时,屏幕上都没有更新。如果你调用像那样的睡眠函数,你没有放弃控制,你一直在运行JavaScript,因此浏览器在此期间不会更新屏幕。它只会在整个insertedSort方法返回时更新,并且浏览器具有3000ms的时间窗口(来自你的setInterval)来处理它自己的东西(渲染)。

不幸的是,您必须找到一种方法来拆分该算法,以便您希望用户明显可见的每个步骤都在其自己的定时回调中发生。

它可能会有以下几点:

function stepOne() {
  do the first bit; 
  setTimeout(secondStep, delay)
}

secondStep() {
  do some more stuff;
  setTimeout(thirdStep, delay)
}

等等。控制动画速度的方法是使用从一步到下一步的延迟参数。

它会变得棘手,特别是因为你不仅仅是尝试动画插入排序,而是各种算法。那么,你是否将它们全部拆分为:insertionSortStepOne / Two / Three,shellSortStepOne / Two / Three?那会很难看。

根据您的雄心壮志以及您希望从这项任务中获得多少,您可以探索ES6(较新版本的JavaScript)的此功能

function*

这让你做的是让你的函数及其所有嵌套循环保持结构化,但是你可以放置它放弃控制的点。之后,它被召回以从它停止的地方继续。您可以使用setTimeout或setInterval来执行此操作。我自己没有尝试过,但它看起来非常酷。