Im not a huge supporter of this idea, but the only solution that would be viable would be returning a specific enum dedicated to this (other than erroring which is equally gross)
local RbxUtility = LoadLibrary("RbxUtility")
local function waitUntilTimeout(event, timeout)
local signal = RbxUtility.CreateSignal()
local conn = nil
conn = event:Connect(function(...)
conn:Disconnect()
signal:fire(...)
end)
delay(timeout, function()
if (conn ~= nil) then
conn:Disconnect()
conn = nil
signal:fire(nil)
end
end)
return signal:wait()
end
-- Example usage
local child = waitUntilTimeout(game.Workspace.ChildAdded, 5)
if (child == nil) then
print("ChildAdded did not fire before timeout")
else
print("New child " .. tostring(child) .. " added")
end
This also makes me wish that we could cancel “delay” functions before they fire. Similar to how you can cancel things in JavaScript (setTimeout, clearTimeout)
I wrote a cancellable delay, with no leaky threads.
local function Delay(duration, func, ...)
if duration <= 0 then
error("duration must be greater than 0", 2)
end
local done = false
local args = {n = select('#', ...), ...}
local container = Instance.new("BoolValue")
local t = tick()
spawn(function()
local v = container:WaitForChild("Cancel", duration)
done = true
if v ~= nil then
v.Parent = nil
else
func(tick()-t, unpack(args, 1, args.n))
end
end)
return function()
if done then
return false
end
done = true
local cancel = Instance.new("BoolValue")
cancel.Name = "Cancel"
cancel.Parent = container
return true, tick()-t
end
end
And there happens to be a signal-timeout function right below that.
local function SignalTimeout(signal, timeout)
local block = Instance.new("BoolValue")
local timedout, results = false, nil
local cancel
local conn = signal:Connect(function(...)
results = results = {n = select("#", ...), ...}
if not cancelTimeout() then
return
end
block.Value = not block.Value
end)
cancelTimeout = Delay(timeout, function()
timedout = true
block.Value = not block.Value
end)
block:GetPropertyChangedSignal("Value"):Wait()
conn:Disconnect()
if timedout then
return false
end
return true, unpack(results, 1, results.n)
end