Time-comparison debounce vs yielding debounce?

What problems are there in a yielding debounce? I’ve heard many people say that a time-comparison debounce is much better than a yielding debounce since “yielding is bad”. But what makes it bad in this situation?
From my limited understanding, whenever an event is fired, a new lua thread is made. Yielding in this thread wouldn’t seriously affect other threads that are supposed to resume.

Yielding debounce

local debounce = false

event:Connect(function()
   if debounce then return end

   debounce = true
   task.wait(3)
   debounce = false
end)

Time-comparison debounce

local lastTime = os.clock()

event:Connect(function()
   if os.clock() < lastTime then return end

   lastTime = os.clock() + 3
end)

Of course the second method looks a lot cleaner. However, my question is regarding the issues in a yielding debounce and what problems they cause.

If yielding isn’t inherently bad, would it not be better to disconnect the connection until the cooldown passes? Something like this:

Disconnecting debounce

local conn

local function onEvent()
   conn:Disconnect()
   task.wait(3)
   conn = event:Connect(onEvent)
end

conn = event:Connect(onEvent)
1 Like

A yielding debounce in one-way communication between two scripts won’t yield the script that fired the event. If you use a remote function/bindable function, then that’s where using a yielding debounce isn’t the best idea, unless the pause is intentional.

1 Like

Yielding gets you into trouble in larger systems. In a small, isolated event trigger like this, it probably doesn’t matter. Some people might disagree with me there, but it’s just not that bad in small contexts like this. I would never yield on main thread though.

I wouldn’t disconnect/reconnect though, because you are crossing paths with logic to both handle the event and hook up the event, which is a bit messy. And if you ever wanted to pass that connection elsewhere to be disconnected by something else, you’d break that since you’re creating a new connection there.


All that being said, I use time comparisons for most debounces. That’s because I can go a little overboard to avoid any explicit yielding. I find it to be a bit cleaner personally.

3 Likes

Time-comparison is definitely cleaner when working with multiple instances of a debounce (such as player-specific cooldowns), since you will need to organize each instance within a table to keep track of everything. Storing the time is usually pretty convenient.

I think, overall, time-comparison simply offers more information about the state of your function (that is, it actually tracks time instead of just running state), and that additional information may provide unforeseen utility in the future, which I think tips the scale.

That all being said, I’m terrible at following this advice and struggle to break the habit of yielding debounces.

1 Like

Ah ok. If possible, please can you explain the problems yielding causes in larger systems?

I didn’t quite understand this. Are you referring to maids/janitors? If so, I’ve never used those so I’m not sure about how they work but I’m guessing they handle your connections in a different thread?

And yeah, I do use time-comparison debounces all the time but I was just confused about why so many people treat yielding debounces as a taboo. I think the main question boils down to “what are the issues related to yielding?”
I do agree with @MysteriousVagabond on the point he made about using a time-comparison debounce when working with multiple instances as you would only want one connection handling all of those instances instead of one connection per instance.

2 Likes