如何在 Coffeescript 中循环使用 setTimout
window.onload = ->
boxOrig1 = 10
boxOrig2 = 30
canvasW = 400
canvasH = 300
ctx = $("#canvas")[0].getContext('2d');
draw = (origin,dimension) ->
ctx.clearRect(0, 0, canvasW, canvasH)
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(origin + boxOrig1, boxOrig1, dimension, dimension)
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
ctx.fillRect(origin + boxOrig2, boxOrig2, dimension, dimension)
for m in [10..100] by 10
t = setTimeout (-> draw(m, 150)), 1000
t.clearTimeout
# draw(m,150)
# alert m
作为练习,上面的代码旨在在画布上绘制一个小设计,暂停一秒钟,然后再次向右绘制 10 个像素。
我可以看到,当我用警报中断循环时(如最后两行注释所示),机制工作正常,但我没有通过 setTimeout 函数获得预期的行为。超时后,设计仅出现在最右侧的位置,跳过中间的增量步骤。
我从其他例子中尝试了很多不同的方法来做到这一点,但这只是融化了我的大脑。有什么建议吗?
window.onload = ->
boxOrig1 = 10
boxOrig2 = 30
canvasW = 400
canvasH = 300
ctx = $("#canvas")[0].getContext('2d');
draw = (origin,dimension) ->
ctx.clearRect(0, 0, canvasW, canvasH)
ctx.fillStyle = 'rgb(200,0,0)'
ctx.fillRect(origin + boxOrig1, boxOrig1, dimension, dimension)
ctx.fillStyle = 'rgba(0, 0, 200, 0.5)'
ctx.fillRect(origin + boxOrig2, boxOrig2, dimension, dimension)
for m in [10..100] by 10
t = setTimeout (-> draw(m, 150)), 1000
t.clearTimeout
# draw(m,150)
# alert m
As an exercise, the code above is meant to draw a little design on a canvas, pause for a second, then redraw it again 10 pixels to the right.
I can see that the mechanics work fine when I interrupt the loop with an alert (as in those last two commented lines), but I'm not getting the expected behavior with the setTimeout function. The design just appears at the rightmost position after the timeout, skipping the incremental steps in between.
I've tried many different ways of doing this from other examples, but it's just melting my brain. Any suggestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Geoff 概述了一种方法(使用
setInterval
并从回调中清除它),因此我将概述另一种方法:在回调中使用setTimeout
。请注意,您应该注意两种方法之间存在细微的时间差异:
setInterval func, 1000
将每 1000 毫秒运行一次该函数;链式setTimeout
会在每次函数调用之间设置 1000 毫秒的延迟。因此,如果draw
花费了 100 毫秒,例如,链接的setTimeout
将相当于setInterval func, 1100
。这可能并不重要,但值得注意。奖励方法:您不必必须放弃循环;您可以一次设置所有超时:
do (m)
是必要的,以便传递给setTimeout
的闭包看到m
的每个值code>,而不仅仅是循环中的最终值。有关详细信息,请参阅我的文章CoffeeScript 干预。最后:我知道这一切一开始看起来很混乱,但 JS 中的计时实际上非常简单,因为该语言是单线程的。这意味着您使用
setTimeout
或setInterval
或任何其他异步函数安排的事件将永远不会在循环期间发生,即使循环是无限的。它们仅在所有代码执行完毕后才会发生。我在我关于 CoffeeScript 的书中更详细地讨论了这一点。Geoff has outlined one approach (using
setInterval
and clearing it from the callback), so I'll outline the other: UsingsetTimeout
from the callback. Something likeNote that there is a subtle timing difference between the two approaches that you should be aware of:
setInterval func, 1000
will run the function once every 1000ms; the chainedsetTimeout
will put a 1000ms delay between each function call. So ifdraw
took 100ms, say, the chainedsetTimeout
would be equivalent tosetInterval func, 1100
. It probably doesn't matter, but it's worth being aware of.Bonus approach: You don't have to abandon your loop; you could just set all the timeouts from it at once:
The
do (m)
is necessary so that the closure passed tosetTimeout
sees each value ofm
, not just its final value in the loop. See my article A CoffeeScript Intervention for more info on this.Finally: I know this all seems very confusing at first, but timing in JS is actually very simple because the language is single-threaded. That means that events you schedule with
setTimeout
orsetInterval
or any other async function will never occur during a loop, even if the loop is infinite. They only occur after all of your code has finished executing. I talk about this in a little more detail in my book on CoffeeScript.这可能更直观地表示为 setInterval:
This might be expressed more intuitively as a setInterval: