How do I use setTimout in Coffeescript within a loop
Geoff has outlined one approach (using setInterval
and clearing it from the callback), so I'll outline the other: Using setTimeout
from the callback. Something like
m = 10
do drawCallback = ->
draw m, 150
m += 10
setTimeout drawCallback, 1000 unless m > 100
Note 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 chained setTimeout
will put a 1000ms delay between each function call. So if draw
took 100ms, say, the chained setTimeout
would be equivalent to setInterval 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:
for m in [10..100] by 10
do (m) ->
setTimeout (-> draw(m, 150)), 100 * m
The do (m)
is necessary so that the closure passed to setTimeout
sees each value of m
, 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
or setInterval
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.
This might be expressed more intuitively as a setInterval:
window.onload = ->
boxOrig1 = 10
boxOrig2 = 30
canvasW = 400
canvasH = 300
ctx = document.getElementById("canvas").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)
count = 10
timer = setInterval (->
if count == 100
clearInterval(timer)
draw(count, 150); count+=10
), 1000