Timer - Scheduling: SetTimeout() and SetInterval()

The Timer script allows execution of code at specified time intervals.

The two key methods to use with Timer are:

  • Timer.SetTimeout(func, delay, ...) : Executes a function, after waiting a specified number of milliseconds.
  • Timer.SetInterval(func, delay, ...): Same as SetTimeout(), but repeats the execution of the function continuously.

Installation

Create a ModuleScript with the name Timer in ReplicatedStorage and paste the content below

--[[
   Timer.lua
      
   Utilities for working with scheduled tasks and time

   by @nidorx <Alex Rodin>
]]   
local RunService = game:GetService("RunService")

local ID         = 1
local TASKS       = {}
local MAX_CALLS   = 30  -- Allows you to define a limit of executions in each interaction

-- max safe int (int53)
local MAX_SAFE_INT = 9007199254740991 -- (2^53) -1

--[[
   Run scheduled tasks.

   Perform a non-blocking run using coroutines
]]
RunService.Heartbeat:Connect(function(dt)
   local toRemove = {}
   
   local count = 0
   for i, task in ipairs(TASKS) do
      if not task.IsRunning then
         task.Elapsed = task.Elapsed + dt * 1000
         if task.Elapsed >= task.Interval then
            task.Elapsed = task.Elapsed - task.Interval

            -- remove when timeout (runs only once)
            if task.IsTimeout then
               table.insert(toRemove, task)
            end
            
            -- run task
            coroutine.wrap(task.SafeExec)()

            count = count + 1
            -- limit interactions
            if count > MAX_CALLS then 
               break
            end
         end
      end
   end

   for _, task in ipairs(toRemove) do
      local pos = table.find(TASKS, task)
      if pos ~= nil then
         table.remove(TASKS, pos)
      end
   end
end)

--[[
   Schedule a task for future execution
]]
local function createTimer(func, delay, isTimeout, arguments)
   local id = ID
   ID = ID + 1

   if delay == nil or delay < 0 then 
      delay = 0
   end

   if type(delay) ~= 'number' then
      error('Number is expected for interval/delay')
   end

   delay = math.min(MAX_SAFE_INT, delay)

   local task     = {}
   task.Id        = id

   -- generates a safe execution of the task
   task.SafeExec  = function()
      task.IsRunning = true

      local success, err = pcall(func, table.unpack(arguments))

      task.IsRunning = false
      task.Elapsed   = 0

      if not success then
         warn(err)
      end
   end

   task.IsTimeout = isTimeout
   task.Elapsed   = 0
   task.Init      = os.clock()
   task.Interval  = delay
   table.insert(TASKS, task)

   return id
end

local Timer = {}

--[[
   Repeatedly calls a function, with a fixed time delay between each call. It returns an interval ID which uniquely 
   identifies the interval, so you can remove it later by calling Timer.Clear(intervalID).

   Important! The interval for the next execution of the task only starts to count when the current execution ends, 
   therefore, a task, even if it takes time, is never executed more than once in parallel


   @see https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval

   @param func (function)  A function to be executed every delay milliseconds (1000ms = 1second).
   @param delay (number)   The time, in milliseconds (thousandths of a second), the timer should delay in between 
                              executions of the specified function
   @param args    (...)    Additional arguments which are passed through to the function specified by func once the 
                              timer expires

   @return intervalID The returned intervalID is a numeric, non-zero value which identifies the timer created by 
      the call to Timer.SetInterval(); this value can be passed to Timer.Clear(intervalID) to cancel the interval.
]]
function Timer.SetInterval(func, delay, ...)
   return createTimer(func, delay, false, {...})
end

--[[
   Sets a timer which executes a function once the timer expires.

   @param func (function)  A function to be executed after the timer expires.
   @param delay (number)   The time, in milliseconds (thousandths of a second, 1000ms = 1second), the timer should 
                              wait before the specified function or code is executed. If this parameter is omitted, 
                              a value of 0 is used, meaning execute "immediately", or more accurately, the next 
                              RunService.Heartbeat event cycle. Note that in either case, the actual delay may be 
                              longer than intended
   @param args (...)       Additional arguments which are passed through to the function specified by func.

   @return timeoutID The returned timeoutID is a numeric, non-zero value which identifies the timer created by 
      the call to Timer.SetTimeout(); this value can be passed to Timer.Clear(timeoutID) to cancel the timeout.
]]
function Timer.SetTimeout(func, delay, ...)
   return createTimer(func, delay, true, {...})
end

--[[
   Used to inactivate schedules created with Timer.SetTimeout or Timer.SetInterval
]]
function Timer.Clear(id)
   for pos, task in ipairs(TASKS) do
      if task.Id == id then
         table.remove(TASKS, pos)
         break
      end
   end
end

return Timer

Timer.SetTimeout

  • The Timer.SetTimeout(func, delay, ...) method will call a function after the time specified in milliseconds (1000 ms = 1 second) has passed.
  • The specified function will be executed once. If you need to run a function multiple times, use the Timer.SetInterval() method.
  • To stop the timeout and prevent the function from executing, use the Timer.Clear(timeoutID) method.
  • The Timer.SetTimeout() method returns an ID which can be used in Timer.Clear(timeoutID) method.

Usage and Purpose

Sometimes it is necessary to program a function call in a specific moment. The Timer.SetTimeout() function is ready to help you with this task-scheduling by postponing the execution of a function until the specified time.

Please bear in mind that the Timer.SetTimeout() function will execute functions once. If you want the function to be repeated multiple times, you should use Timer.SetInterval().

local Timer = require(game.ReplicatedStorage:WaitForChild('Timer'))

local function MyFunction(name)
   print("Hello, "..name)
end

Timer.SetTimeout(MyFunction, 3000, "Alex")
Timer.SetTimeout(MyFunction, 6000, "John")

Syntax

As you can see in the snippet above, the Timer.SetTimeout() function can contain several parameters:

Timer.SetTimeout(func, delay, param_one, param_two, ...)

First of all, the Timer.SetTimeout() method should contain the function that you intend to apply. The second parameter sets a time when the specified function is to be called. However, it is optional, and the default value is 0 (meaning execute “immediately”, or more accurately, the next RunService.Heartbeat event cycle). You can also specify parameters for the function you have indicated previously.

Parameter Description
func (Required). Specifies the function that will be executed.
delay (Not required). Specifies the time the function will be executed. 0 milliseconds by default.
param_one, param_two, ... (Not required). Parameters passed to the function.

Timer.SetInterval

  • The Timer.SetInterval(func, delay, ...) method executes a specified function multiple times at set time intervals specified in milliseconds (1000ms = 1second).
  • The Timer.SetInterval() method will keep calling the specified function until Timer.Clear(intervalID) method is called.
  • The Timer.SetInterval() method returns an ID which can be used by the Timer.Clear(intervalID) method to stop the interval.
  • If you only need to execute a function one time, use the Timer.SetTimeout(func, delay, ...) method.

Usage of Timer.SetInterval

It could be defined simply as a method which allows you to invoke functions in set intervals.

The Timer.SetInterval() function is similar to the Timer.SetTimeout() method. How are they different? Well, Timer.SetTimeout() calls functions once. However, with the set interval method you can invoke them multiple times.

Let’s say you need to display a message every 3 seconds. By applying the Timer.SetInterval() function, you will be able to perform this task.

The following code example shows the way the message is set to be displayed every 3 seconds:

Example

local Timer = require(game.ReplicatedStorage:WaitForChild('Timer'))

local count    = 0
local param1   = "Hello"
local param2   = "World!"

Timer.SetInterval(function(a, b)

   count = count + 1
   print(a..", "..b.." Count = "..count)
  
end, 3000, param1, param2)

Syntax

See the code snippet below. This is the syntax of the function that you should keep in mind:

Timer.SetInterval(func, delay, param_one, param_two, ...)

As you can see, the Timer.SetInterval() can contain three parameters. The first one identifies which function is going to be applied in the set time intervals. As you might expect, you also should include the milliseconds to set the frequency of your function. Additionally, you can specify parameters for the function to be applied.

Parameter Description
func (Required). Defines the function to run.
delay (Not required, defaults to 0 = RunService.Heartbeat). Defines how often the function will be executed (in millisecond intervals).
param_one, param_two, ... (Not required). Defines any additional function parameters.

Stopping the Function

In some cases, you might need to stop SetTimeout() or SetInterval() from being executed before the times comes. You’ll need to use the Timer.Clear(id) method. It’s meant to stop the timer set by using the Timer.Set*() function.

The Timer.SetTimeout() and Timer.SetInterval() returns a variable called ID. You can then use it to call the Timer.Clear(ID) function.

Timer.Clear(ID) itself has no return value: the only result is achieves is making Timer stop SetTimeout() or SetInterval() from running.

Example 1

local Timer = require(game.ReplicatedStorage:WaitForChild('Timer'))

local function MyFunction(name)
   print("Hello, "..name)
end

local timeoutId1 = Timer.SetTimeout(MyFunction, 3000, "Alex")
local timeoutId2 = Timer.SetTimeout(MyFunction, 6000, "John")
local timeoutId3 = Timer.SetTimeout(MyFunction, 9000, "Mary")


Timer.Clear(timeoutId1)
Timer.Clear(timeoutId3)

Example 2

local Timer = require(game.ReplicatedStorage:WaitForChild('Timer'))

local count    = 0
local param1   = "Hello"
local param2   = "World!"

local intervalId

intervalId = Timer.SetInterval(function(a, b)

   count = count + 1
   print(a..", "..b.." Count = "..count)

   if count > 3 then
      print("Bye")
      Timer.Clear(intervalId)
   end
  
end, 3000, param1, param2)
19 Likes

This is very useful! tysm man <3