Neither should run faster than the other, at least noticeably to the point where you should be concerned. They’re pretty close to each other in terms of how they operate. On one hand you’re yielding the thread until the next event, and on the other hand you’re waiting for the event to fire to then create a sudo-thread to run the code. It’s just a difference in the order of operation.
Instead of looking into performance for something as minimal as this, you should be considering the possibilities of using them instead.
For example, you can make a counter based in time with the first example:
local s = 0
local duration = 5
while true do
-- some code!
if s > duration then
break
end
s = s + RunService.Heartbeat:Wait()
end
While you could do this with the second example you gave, it’s not recommended since each function call is its own thread, which means if you yield one call, the next call can and will still go through.