LessonsAdvanced: Bigger programsLesson 43

Timers and waiting

Make something happen later, or again and again, without freezing the program: wait, send in, the pendingMessages and cancel.

  • Advanced
  • Lesson 43 of 83
  • About 9 minutes
  • 8 examples

Waiting

wait pauses the handler for a time, in seconds, milliseconds or ticks (sixtieths of a second):

ExampleRun it in the playground
put the milliseconds into tStart
wait 250 milliseconds
put the milliseconds - tStart into tTook
put tTook >= 240 and tTook < 1000
Output
true

While a plain wait lasts, the whole program waits with it: a click is not answered, and a timer does not fire. That is fine for a moment's pause, but not for anything longer. wait ... with messages lets the rest of the program carry on during the wait, and wait until waits for a condition to become true:

ExampleRun it in the playground
local sDone

on finish
   put true into sDone
   put "finished"
end finish

put false into sDone
send "finish" to me in 300 milliseconds
wait until sDone with messages
put "waited for it"
Output
finished
waited for it

Later: send in

Usually you do not want to wait at all: you want something to happen later while the program goes on. send (Messages and events) with in and a time does exactly that. It sets a timer and returns at once; when the time comes, the message arrives like any other:

ExampleRun it in the playground
on ring pTimes
   put "Ring!" && pTimes && "times"
end ring

send "ring 3" to me in 300 milliseconds
put "The timer is set."
Output
The timer is set.
Ring! 3 times

The message is text, so the values for its parameters go after its name, as you would type them: here 3. To pass a value from a variable, join it in: send "ring" && tCount to me in 1 second.

Again and again

A handler that sets a timer for itself runs again and again: this is how a clock ticks, a game moves, or a program checks for new mail. Give it a way to stop, or it goes on until the stack closes:

ExampleRun it in the playground
local sCount

on countUp
   add 1 to sCount
   put "count" && sCount
   if sCount < 5 then
      send "countUp" to me in 100 milliseconds
   end if
end countUp

put 0 into sCount
countUp
Output
count 1
count 2
count 3
count 4
count 5

Unlike a repeat loop, a handler that sends itself lets everything else happen between its runs: clicks are answered, fields can be typed in, and other timers fire. It is the right shape for anything that goes on over time.

Timers still to come: cancel

send ... in leaves the timer's id in the result. the pendingMessages lists every timer still to fire, a line each (its id, when it fires, the message and where it goes), and cancel stops one by its id:

ExampleRun it in the playground
on alarm
   put "alarm!"
end alarm

on nudge
   put "the nudge arrived"
end nudge

send "alarm" to me in 5 seconds
put the result into tAlarmID
send "nudge" to me in 200 milliseconds
put the pendingMessages into tPending
filter tPending with "*,alarm,*"
put the number of lines of tPending
cancel tAlarmID
put the pendingMessages into tPending
filter tPending with "*,alarm,*"
put the number of lines of tPending
Output
1
0
the nudge arrived

The IDE has timers of its own, which is why the example filters the list to its own message. A program that stops (a game that ends, a window that closes) should cancel its timers, so none fires into something that is no longer there:

ScriptPut it in an object's script
on closeCard
   repeat for each line tLine in the pendingMessages
      if item 3 of tLine is "countUp" then
         cancel item 1 of tLine
      end if
   end repeat
end closeCard

Measuring time

the milliseconds counts thousandths of a second, and the seconds whole seconds, both from a fixed moment long ago. One reading means little; the difference between two is a length of time:

ExampleRun it in the playground
put the milliseconds into tStart
repeat 100000 times
   add 1 to tCount
end repeat
put "That took" && the milliseconds - tStart && "ms"
Output (yours will differ: it changes from run to run)
That took 21 ms

The number depends on the computer, so the example's Output is only one run's. Making code fast uses this to compare two ways of doing the same thing.

Try it yourself

Write a countdown: a handler countDown that puts its number, then sends itself the number one less, 200 milliseconds later, and puts Go! when it reaches 0. Start it from 3.

Show a solution
ExampleRun it in the playground
on countDown pFrom
   if pFrom > 0 then
      put pFrom
      send "countDown" && pFrom - 1 to me in 200 milliseconds
   else
      put "Go!"
   end if
end countDown

countDown 3
Output
3
2
1
Go!

Words in this lesson

Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.