Javascript 递归函数和setTimeout()问题
我有一个脚本在画布上画了一堆线,但它非常紧张,所以在渲染时会将浏览器冻结几秒钟。我添加了setTimeout(),这样浏览器就不会冻结,它实际上会弄乱我的脚本。这很难解释,所以我在网上有两个例子: 不带setTimeout(): 使用setTimeout(): 请注意,我只更改了整个脚本中的一行,即第69行:Javascript 递归函数和setTimeout()问题,javascript,canvas,settimeout,Javascript,Canvas,Settimeout,我有一个脚本在画布上画了一堆线,但它非常紧张,所以在渲染时会将浏览器冻结几秒钟。我添加了setTimeout(),这样浏览器就不会冻结,它实际上会弄乱我的脚本。这很难解释,所以我在网上有两个例子: 不带setTimeout(): 使用setTimeout(): 请注意,我只更改了整个脚本中的一行,即第69行: 没有setTimeout():vLoop() 使用setTimeout():setTimeout(vLoop,1) 您可以同时调用vLoop的4个递归函数。这里的问题是,setTimeou
没有setTimeout():
vLoop()代码>
使用setTimeout():setTimeout(vLoop,1)代码>
您可以同时调用vLoop
的4个递归函数。这里的问题是,setTimeout
是非阻塞的,而as递归是阻塞的。所以基本上你现在有了4个并行运行的函数,而不是顺序运行的函数
另一个问题是,所有4个引用并扰乱全局状态,导致整个程序中断
您可以同时调用vLoop
的4个递归函数。这里的问题是,setTimeout
是非阻塞的,而as递归是阻塞的。所以基本上你现在有了4个并行运行的函数,而不是顺序运行的函数
另一个问题是,所有4个都引用并弄乱了全局状态,导致整个程序中断。发生的是setTimeout()
将所有执行延迟到以后。不幸的是,到那时,您的全局变量都从初始循环移动到了它们的结束位置,因为它在绘制第一条线之前就完成了
如果您将超时时间进一步向上移动(这样您使用的共享变量在绘图时间之前不会受到影响),您可以实现您所追求的目标,例如:
setTimeout(function() {
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);
});
那么这就行了(但这很危险,秩序并不是绝对的夸夸其谈!)
。不幸的是,到那时,您的全局变量都从初始循环移动到了它们的结束位置,因为它在绘制第一条线之前就完成了
如果您将超时时间进一步向上移动(这样您使用的共享变量在绘图时间之前不会受到影响),您可以实现您所追求的目标,例如:
setTimeout(function() {
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);
});
那么这就行了(但这很危险,秩序并不是绝对的夸夸其谈!)
.正如其他人所暗示的,这里的问题是,你一次画一个象限的线。只要调用了SetTimeout
方法,并且第一个vLoop
返回,代码就会继续运行到下一个drawVertical
,从而更改所有全局变量,依此类推
你需要做的是同步你如何调用vLoop和你如何改变globals
这基本上就是解决方案:
替换
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);
。。。与
var q = new Array();
q[0] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y];
q[1] = [c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y];
q[2] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0];
q[3] = [c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0];
drawQuadrant(q, 0);
将drawVertical
功能替换为
function drawQuadrant(q, i)
{
var r = q[i];
c__ = r[0];
step__ = r[1];
stepInt__ = r[2];
bigStep__ = r[3];
xStart__ = r[4];
xEnd__ = r[5];
yStart__ = r[6];
yEnd__ = r[7];
vLoop(q,i);
}
将vLoop
函数原型更改为如下所示
function vLoop(q,i)
最后将递归的vLoop
调用(从vLoop内部)替换为
if((xStart\uuu0)和&(xStart\uuu0
最后一块是确保象限不会相互重叠的地方。正如其他人所暗示的,这里的问题是,您一次画一个象限的线。只要调用了SetTimeout
方法,并且第一个vLoop
返回,代码就会继续运行到下一个drawVertical
,从而更改所有全局变量,依此类推
你需要做的是同步你如何调用vLoop和你如何改变globals
这基本上就是解决方案:
替换
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y);
drawVertical(c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0);
drawVertical(c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0);
。。。与
var q = new Array();
q[0] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2+50,y];
q[1] = [c,step,stepInt,bigStep,xStart,xEnd,y/2+50,y];
q[2] = [c,-1*step,-1*stepInt,-1*bigStep,xStart,xEnd,y/2-50,0];
q[3] = [c,step,stepInt,bigStep,xStart,xEnd,y/2-50,0];
drawQuadrant(q, 0);
将drawVertical
功能替换为
function drawQuadrant(q, i)
{
var r = q[i];
c__ = r[0];
step__ = r[1];
stepInt__ = r[2];
bigStep__ = r[3];
xStart__ = r[4];
xEnd__ = r[5];
yStart__ = r[6];
yEnd__ = r[7];
vLoop(q,i);
}
将vLoop
函数原型更改为如下所示
function vLoop(q,i)
最后将递归的vLoop
调用(从vLoop内部)替换为
if((xStart\uuu0)和&(xStart\uuu0
最后一块是确保象限不会相互重叠的地方。你能告诉我们vLoop
的实际代码吗vLoop
的实际代码仍然是单线程的,所以说它们并行运行并不准确。@NickCraver时间拼接执行实际上是它们并行运行。使用setTimeout与时间拼接有何不同?@Raynos-您永远不会在同一时间多次进入该方法,这是parallel:)@NickCraver的定义,但您将在递归执行的函数集中一次以上。单个函数不会并行运行,但递归执行会并行运行。@Raynos-它不会…在任何情况下,他正在运行的任何代码行都不会同时运行。它们仍然是单线程的,所以说它们并行运行并不准确。@NickCraver Time拼接执行实际上是并行运行的。使用setTimeout与时间拼接有何不同?@Raynos-您永远不会在同一时间多次进入该方法,这是parallel:)@NickCraver的定义,但您将在递归执行的函数集中一次以上。单个函数不会并行运行,但递归执行会并行运行。@Raynos-它不会…在任何时候,他运行的任何代码行都不会同时运行,这只是将整个绘图过程推迟到以后。一旦块开始运行,您仍然存在冻结浏览器的原始问题。@Musaul-It'l