Avoid using while true do & while wait() do!

Introduction


Have you ever used while true do before and it breaks your code or completely stops your Roblox Studio from functioning? Well, you have come to the right place! I have seen heaps of posts regarding while true do on the Roblox DevForum and this tutorial will cover all the information you need to prevent this from happening ever again. So, lets begin!

What we will cover in this tutorial:

  • How is this tutorial important to understand?
  • What is while true do?
  • Why is while true do so bad and is there another way to use it?
  • What is task.wait() and is it better than wait()?

How is this tutorial important to understand?

This tutorial is highly recommended for beginners as it covers both good and bad practices when it comes to using while loops. And if you are an intermediate developer and you use while wait() do, this tutorial will explain why that is bad practice too!


What is while true do?

So to start off what is while true do? Many of you probably already know what while true do is but I am going to explain it to the beginner developers. while true do is a loop that will repetitively run code inside of it instantaneously unless the condition is set to false. This is also known as a while loop:

while true do
    print("Hello world!")
end

Now you may be thinking what could possible be wrong with this code and it looks fine. WRONG. When you test this out in Roblox Studio, it will either send you an error message in the output and break your code or crash Roblox Studio for you making it impossible to playtest your game.


Why is while true do so bad and is there another way to use it?

Loads of Roblox developers have used while true do once before in their code and that’s alright because we are all learners here and we all make mistakes which is what makes us human but its now time to stop using while true do.

There have been many posts on the Roblox DevForum regarding while true do and an example of a post may be: “Is it worth using while true do?” or “Why does while true do break my game?” and this my friend is the solution to all those posts.

Since while true do is an infinitely running loop which runs code inside it instantaneously, it causes the script to become exhausted therefore breaking your code and crashing your Roblox Studio. Most of the time you may have seen an error message sent to the output saying: “Script timeout: exhausted allowed execution time”.

This basically says the script timed out and we need to add a delay (in seconds) inside of it so the script doesn’t get exhausted and timeout again. So, lucky for us we can still use the while loop but we just need to insert a delay to it so that it doesn’t break the game or crash Roblox Studio.

It is highly recommended that you put a 0.8 - 1 second delay (or higher) into the while loop so the script doesn’t timeout:

while task.wait(1) do
    print("Hello world!")
end

OR

while true do
    print("Hello world!")
    task.wait(1)
end

But wait a second, what is task.wait(1)? Why not use wait(1)?

Lets explore that right now!


What is task.wait() and is it better than wait()?

"task.wait() yields the current thread until the given duration (in seconds) has elapsed and then resumes the thread on the next Heartbeat step." - @WallsAreForClimbing

In simple terms, task.wait() is an improved version of wait().

local myElapsedTime = task.wait(2) --> Wait for 2 seconds
print(myElapsedTime) --> My result: 2.0139438999999584

How is this helpful did you say? Well, since while true do needs a delay in it so the script doesn’t get exhausted and timeout, task.wait() is the perfect solution to this!

Final result:

while task.wait(1) do
    print("Hello world!")
end

OR

while true do
    print("Hello world!")
    task.wait(1)
end

Conclusion

Congratulations! You have now just made while true do functional for your game!

I hope this tutorial was helpful to many developers out there who are just discovering this dilemma. If you have any questions please PM me.

Helpful Resources:

34 Likes

This is true, and task.wait() is more accurate than wait().

But.

Wouldn’t this show that the second one is more accurate?

3 Likes

wait() is accurate but not as accurate as task.wait(). It updates much faster than wait(). There really is no reason to use wait() over task.wait().

You can read more on it here:

2 Likes

I know it is faster, but a point of it being faster is that it will wait for a more accurate time, but in the example given the old wait() function was closer to 2 than the new task.wait() function?

1 Like

[This is a nit-pick reply]
I think the title is a bit misleading/off-putting. There’s nothing wrong with while true do in this case:

while true do
     task.wait(3)

     --// Rest of code
end

While this is functionally the same as while task.wait(3) do, it’s syntactically clearer and more precise to do while true do and then have the rest of the function follow. Again, I realize this is a nit-pick, but I still think it’s worth noting, because it puts it at odds with the topic title in it’s current form “Avoid using while true do & while wait() do!”. This topic might be better renamed as “Best practices for while loops?”

17 Likes

wait() will return the time elapsed while task.wait() does not. Though I’m still not sure why people use Spawn() and Wait().

1 Like

Instead of using while loops with task.wait, which yields, I prefer to connect to heartbeat or any of the other render functions instead so it doesn’t yield. Not quite as pretty and a bit less intuitive, but still gets the job done and to my knowledge doesn’t yield the thread. It should also work with unlocked frame rate as it uses deltatime instead of an arbitrary wait time

local Interval = 1
local lastActivation = 0

RunService.Heartbeat:Connect(function(dt)
      if lastActivation >= Interval then
            DoWork()
            lastActivation = 0
      else
            lastActivation += dt
      end
end)
3 Likes

Why from 0.8? This doesn’t time out for me.

while task.wait() do

end
1 Like

I’ve never, NEVER, had scripts time out for me or studio crash despite having atleast a dozen using a setup like this

while true do
   --insert action here
end

or like above but with a wait time of under 1.

If that somehow crashes your studio or times out your scripts, quite frankly, your studio or system may just be unstable/unfit. Or you had an unrealistically excessive amount of scripts in a single place, my assumption, because I don’t know.

1 Like

Although you have the right idea in some cases, I don’t think you sufficiently understand the practices you’re trying to teach and that leads you to providing wrong teaching material on this topic. This thread is effectively a long form post of reminding developers not to leave a loop body without a yield at the end of an iteration or it may hang the environment it’s running on.

The main problem with while loops are either lack of intervals by nature of a yielding condition (be it task.wait or a yielding function call) or yielding at the start of an iteration which makes the loop somewhat unmaintainable. Ideally you only want to wait as in when you need to.

Using wait in the conditional part of a while loop is bad practice whether or not you provide a value. Wait will provide a return value which will render the conditional of a while loop truthy but you’re changing that evaluation every iteration. In general, you should strive to avoid a yield as the conditional and instead make sure that the evaluation is static. If you need to return something, it should be ensured that the function stack yields as little as possible or doesn’t at all.

That being said, while loops themselves are not bad practice, so the thread is misleading by saying to “avoid both” but then suggesting those exact same things with changes to them, particularly the former by having a yield condition at the end of the loop body and the latter by giving an argument to wait. It is generally already expected that a non-yielding while will crash.

Not for reason of crashing but of practice, I would recommend taking a look at this resource which directly explores the real problem with while loops which is abusing the conditional:

7 Likes

that moment when i pcall in a while true do end and i forget about the task.wait() after the pcall (if unsuccessfull)

jokes aside this is a good post, might use it

1 Like

This is actually better in my opinnion, but in alot of my projects, I suffer from lag in while loops that check for each and every bool value and it just shoots remote events repeatedly for the player’s gun. I made 3 more weapons since a pistol wasnt enough and 3 because I use GUI for my weapons since there is more guns, it also would have another 3 while loops running at the same time. I think i might make a post on how you can help me with this before I even give it away to my brother.

1 Like

They both return elapsed time.

2 Likes

Only wait() does:


22 seconds elapsed in the game.

2 Likes

I know most people do

while true do
 -- Code
 task.wait(1)
end

But what about

while script.Parent do
 -- Code
 task.wait(1)
end

or

repeat
 -- Code
 task.wait(1)
until not script.Parent

?

I see almost no one talk about that.
Theoretically if you do script.Parent the code should execute until the script is destroyed or parented to nil.

OH here is another fun loop.

function doThing()
 -- Code
 task.wait(1)
 doThing()
end

doThing()

Although that one might stop working if there is a limit on how often recursion can be done.

Edit: Also yes, I already know destroying a script stops it’s execution.

2 Likes

Destroying a script kills the thread the script depends on, ie: preventing any wait statements from resuming since its dead

1 Like

I completely agree. This post is structured very odd because it makes it seem like you should use while true do, but that’s not the point of the post at all. The point of the post seems to be reminding people to add task.wait() when using this loop.

When I finished reading this post I was so confused…Telling us to stop using it, but then concluding the post by telling us to continue using it.

1 Like

TL;DR
The problem is not in the loop itself, it’s in the absence of a “wait”, meaning it will run at an incredibly fast speed, causing the game to lag or even crash.

This actually did leave me wondering if destroying a script also destroys connections made to events.

I often feel like that if a script is destroyed that events just keep existing and stacking up in memory but with no code to execute because the script that holds the function is gone.

The difference you are seeing is approximately 1/71th of a second off (less than one frame). This is because task.wait resumes on the first frame after the time has elapsed. It will be at most one full frame off (it is accurate to within one frame). The reason that it appears less precise in your example is purely by chance.

wait can also do this too, but it will be at most two full frames off, and often times will be worse, particularly when the server is under high stress, because wait works differently under the hood.

Depending on how long different frames happen to take, task.wait and wait can both be off by that amount, it just depends how long it will be until the next frame, and frames can take any amount of time and almost definitely will across different tests. task.wait is still much more accurate due to it always resuming on the first frame.

2 Likes