Brodgar client

hafen.timer: Scheduling

Run a function later, once or repeatedly. Use it for polling a value with no change event, or for waiting for the character data that streams in after SessionEnteredWorld. Unprotected, run on the UI thread, cancelled for you on reload or disable.

hafen.timer():after(3, function() hafen.log():write("3 seconds later") end)

local tick_timer = hafen.timer():every(1, function() hafen.log():write("tick") end)
tick_timer:cancel()

Schedule

Method Returns Permission Description
hafen.timer():after(seconds, fn) handle Unprotected Run fn() once, seconds from now.
hafen.timer():every(seconds, fn) handle Unprotected Run fn() every seconds, starting seconds from now, until cancelled or the addon goes away.
Rule Detail
Arguments Both raise unless given a number and a function. A negative delay counts as 0.
Tick resolution A callback fires on the first tick at or after its due time: the interval is a floor.
A repeater’s schedule The next run is due one interval after the previous due time, not after the callback finished. A slow callback does not push the schedule out. It fires at most once per tick, so a stall is not made up for. An interval of 0 fires once a tick, and you pay for its body every frame.
A delay of 0 Due on the tick it was made on. The client fires Update (the bus’s and every surface’s) before the due timers. A 0 scheduled from an Update handler runs later in the same step. One scheduled from a file body, a console line or a handler dispatched into a widget tree waits for the next step. That makes :after(0, fn) the way off a held tree.
Order Your timers due on one tick fire in the order you made them. Between addons there is no order, nor between a timer and another addon’s handler for the same moment.
An error in fn Logged and isolated. It does not cancel the timer, so a repeater whose body throws throws again every tick: cancel it yourself when the failure is permanent. A body that fails the client itself (stack, memory) stops your addon, timer and all.

The timer handle

What :after and :every hand back: the timer itself, answering for its own schedule.

Method Returns Permission Description
timer:interval() number Unprotected The seconds between runs. 0 for a one-shot, and for a repeater made with a period of 0 or less (:repeats() tells them apart).
timer:repeats() boolean Unprotected true for one made with :every, false for :after.
timer:due() number \| nil Unprotected Seconds until it next runs. 0 when due on this tick. nil once dead.
timer:alive() boolean Unprotected Still scheduled: false once cancelled, and once a one-shot has run.
timer:cancel() the handle Unprotected Stop the timer. Safe to call more than once, and on one that has fired.
timer:info() table Unprotected A snapshot carrying interval, repeats, alive, and due while alive.
Rule Detail
tostring(timer) Timer(every 5s), Timer(after 2s, fired) or Timer(after 2s, cancelled).
Closed A verb the timer lacks raises naming the ones it has. timer.cancel = nil is refused.

Read what is scheduled

hafen.timer() is a collection of the timers your addon has running, holding the handles :after and :every gave you, so == finds one you kept.

Method Returns Permission Description
hafen.timer():list(filter) handle[] Unprotected Every timer still scheduled.
hafen.timer():count(filter) number Unprotected How many are still scheduled.
hafen.timer():find(filter) handle \| nil Unprotected The first that matches.
Rule Detail
filter Omitted, or a function called with each handle, which answers the reads above. A timer has no name, so the string filter is refused.
A collection is an object # and [n] on it are refused. :list() is the array.
hafen.timer():every(1, function() hafen.log():write("tick") end)
hafen.log():write(hafen.timer():count() .. " timer(s) running, "
                  .. hafen.timer():count(function(timer) return timer:repeats() end) .. " of them repeating")
for _, timer in ipairs(hafen.timer():list()) do timer:cancel() end

See Also