How does RunService work?

Hello, so, I already searched on
Roblox Developer Site, but I still don’t understand how RunService works and I haven’t found any Post on DevForum explaining it.
Could someone explain to me how RunService works?

9 Likes

RunService has a lot of different functions and events, can you clarify? The main usage for it is running code every frame, for which it has three events: Heartbeat, Stepped, and RenderStepped. These all run at different parts of the frame, for which Fractality_alt has made a helpful diagram:

9 Likes

Alright, I’ll teach you the basics, so you’ll be able to follow the other tutorials on the DevForum.

The RunService is basically a service that gives you information about the time and the context the script is running (Example: is running on the server).
It has three super important events, the RenderStepped, Stepped and Heartbeat, each of them with for different usages.
These events fires multiple time per second, being a good replacement for the wait() function.
Each one of them fires at a different Frame render state (you can see it on the chart that @posatta uploaded above), being more or less convenient to use for different situations.

TL;DR RunService has events that fires many times per second and a function telling you the context you are running the script into (Example: you are in studio).

10 Likes

Check out the documentation on RunService and the Task Scehduler.

1 Like

But in what use would I need to know where the script is running? and what’s the difference between using RenderStepped, Stepped and Heartbeat?

2 Likes

Yes, I would like to understand these three events (RenderStepped, Stepped and Heartbeat)

2 Likes

Let’s say you are testing your game, and in your script you have a function that uses the player UserId.
Since in a local server your player hasn’t got an UserId, it would throw an error.
If you want to test it without getting stuck at that point of the script the ways are three:

  • You can use pcall(), but that’s useless and not the best thing for performances.
  • You can comment out this piece of code, but it’s pretty annoying to do so everytime you need to test it
  • You can use an if statement to check if you are in studio, so this chunk of code doesn’t run

The main difference is that they all fire at different “step” of the frame render, meaning that RenderStepped fires before the render (generation) of the Frame, Stepped fires prior to the physics being simulated, and Heartbeat fires after the physic gets simulated

4 Likes

I didn’t know that UserId doesn’t exist in RobloxStudio, but I understood, thanks man!
Just one more question: Is it better to use (While True do) or (RunService)? Is there any difference?

2 Likes

It’s better to use RunService, since wait can be laggy. To implement it you can do:

game:GetService("RunService").Stepped:Connect(function() --code here...

And another one thing: RenderStepped can only be used from a local script since it’s based on the frame render, that it’s done by the client.
So in a server script you can connect a function only to Stepped and Heartbeat, while on the client you can use all the three events.

Have a good day! :smiley:

3 Likes

About lag, is any better to avoid it?

Yes, it’s better RunService. You should avoid wait() whenever you can

1 Like

As the chart shows, they fire at different times during the frame. RenderStepped fires before stuff renders, so it should be used for stuff like a custom camera that needs immediate feedback. Stepped fires before physics are calculated, so it should be used for custom physics (manually setting velocity every frame, etc). Heartbeat fires at the end of the frame, so it should be used to run something every frame without it blocking anything from happening. Expensive code in either RenderStepped or Stepped will delay relay/physics, respectively, so it’s better to put whatever possible in a Heartbeat event.

4 Likes

Sorry for bumping this up but I have a question about that, so does that mean that RenderStepped and Stepped basically tells the game to make the code inside them before rendering or calculating the physics, so it yields them until the code inside finishes?

Maybe I said this in a weird way so I will do a better example:

local runS = game:GetService("RunService")
runS.RenderStepped:Connect(function()
       wait(10) 
end)
runS.Stepped:Connect(function()
       wait(10)
end)

So would these codes yield the physics simulations and the renderings by 10 seconds?

1 Like

RenderStepped and Stepped don’t have to complete before rendering and physics happen, they just need to stop. Yielding will allow rendering and physics to occur, since the function isn’t running while that’s going on. On the other hand, something like this will block rendering:

local runS = game:GetService("RunService")

local frameCount = 0

runS.RenderStepped:Connect(function()
	local current = frameCount + 1
	frameCount = current
	
	print("Frame number", current, "starting!")
	
	for i = 1, 1e7 do
		local x, y = math.modf(53 ^ 7 / 4) -- some random math that isn't that expensive but we're running it a million times for whatever reason
	end
	
	print("Frame number", current, "ending!")
end)

You’ll notice for this, each RenderStepped function has to end (as shown by the print that happens when it’s ending) before the next one starts. It looks something like this:
image

On the other hand, if it yields, other stuff is allowed to run and rendering continues as normal. By the time it resumes, several other frames may have rendered. Example of how changing the code would look:

local runS = game:GetService("RunService")

local frameCount = 0

runS.RenderStepped:Connect(function()
	local current = frameCount + 1
	frameCount = current
	
	print("Frame number", current, "starting!")
	
	--[[
	for i = 1, 1e7 do
		local x, y = math.modf(53 ^ 7 / 4) -- some random math that isn't that expensive but we're running it a million times for whatever reason
	end
	]]
	
	wait(1)
	
	print("Frame number", current, "ending!")
end)

And you can see how many frames are able to render before the first one finishes:
image


Putting expensive code like our first example every frame will tank FPS regardless of whether you connect to RenderStepped or Heartbeat, but there’s a noticeable difference. Try jumping when you’re connected to each event, which you can do by just replacing RenderStepped with Heartbeat, and see if you notice a difference. Which part of the frame the slowdown is on can affect how responsive pressing something feels, and can make UX feel somewhat better even if things are a bit slow.

3 Likes

But whats the reason for heartbeat being less expensive to FPS than render stepped?

Is it because Render Stepped fires faster therefore it ends up making the same code more times?

It’s not less expensive to FPS. Both cause it to tank. It’s a matter of what time during the frame it occurs, and what it’s blocking from happening.

If there’s a long time between user input and when the frame renders, it’ll feel unresponsive. If the delay happens later, after everything’s rendered and all, it’ll still lower the FPS but it will feel more responsive to the player. Like I said,

The notable difference isn’t in FPS, it’s in responsiveness.

3 Likes

Still cant understand how would when the thing happen even matter.

If a thing will happen when another thing finishes “happening” then wouldn’t making that another thing happen again and again be as bad as a thing that happens before another thing happen and that same another thing keeps on happening over again?

Like this:

(Its how I am thinking right now)
Heartbeat:

Physic finishes, Fire, Physic finishes, Fire.

RenderStepped:

Render starts, Fire, Render starts, Fire.

Like the diagram I first posted shows, and Crazyman’s wiki link says, RenderStepped happens before rendering. If RenderStepped is taking a long time, that stops rendering from happening.


Edit for clarification: Heartbeat taking a long time will still slow down the frame overall, but it’s not between any steps. It’s at the end of the frame. A long time between user input and render will make the response to user input seem delayed and unresponsive, but a long time between different frames will just lower how many frames happen overall.

5 Likes

So render stepped is the only one that stops the thing thats mainly focused of happening out of all these three (render) ?

Just understood the reason for heartbeat and render stepped having a different responsiveness.

2 Likes

Yeah. Stepped is before some physics stuff happens, but the only place you need to worry about putting expensive code is really RenderStepped.

4 Likes