La propiedad Workspace.SignalBehavior controla si los controladores de eventos se activan de inmediato o se diferidos. Se recomienda la opción Enum.SignalBehavior.Deferred, que ayuda a mejorar el rendimiento y la corrección del motor. Los controladores de eventos para eventos diferidos se reanudan en el siguiente punto de reanudación, junto con cualquier controlador de eventos que se active recientemente.
El siguiente diagrama compara el comportamiento de eventos de Immediate y el comportamiento de eventos de Deferred.
- Con el comportamiento Immediate, si un evento activa otro evento, el segundo controlador de eventos se activa de inmediato.
- Con el comportamiento Deferred, el segundo evento se añade al final de una cola y se ejecuta más tarde.
El tiempo total requerido no cambia, pero el orden es diferente.

La "re-entrancia" previene que los eventos se activen continuamente entre sí cuando alcanzan cierta profundidad. El límite actual para esto es 10.
Beneficios de los eventos diferidos
El comportamiento Immediate tiene algunas desventajas. Por cada instancia añadida a tu juego, propiedad que cambia, o algún otro disparador que se invoca, el motor necesita ejecutar código Luau antes de que ocurra cualquier otra cosa.
- Para cambiar 1,000 propiedades, potencialmente necesitan ejecutarse 1,000 fragmentos de código después de cada cambio.
- Pueden ocurrir errores extraños y difíciles de diagnosticar, como un evento de eliminación que se activa antes de que algo haya sido añadido.
- Los sistemas críticos para el rendimiento pueden generar eventos que requieren que vuelvan a Luau.
- Los controladores de eventos pueden hacer cambios en el lugar o activar otros eventos cada vez que se activa un evento.
- Un evento puede activarse múltiples veces a pesar de ser redundante, como un cambio de propiedad que ocurre dos veces.
Al tener porciones específicas del ciclo de vida del motor en las que Luau puede ejecutarse, el motor puede ganar un rendimiento mejorado al hacer una serie de suposiciones:
- Los sistemas críticos para el rendimiento no necesitan ceder a Luau, lo que lleva a ganancias de rendimiento.
- A menos que el mismo motor lo cambie, el lugar nunca cambia fuera de un punto de reanudación.
Puntos de reanudación
Después de ser diferido, un controlador de eventos se reanuda en el siguiente punto de reanudación. Actualmente, el conjunto de puntos de reanudación incluye:
- Procesamiento de entrada (se reanuda una vez por cada entrada a procesar, véase UserInputService)
- Reanudación de scripts de espera heredados como wait(), spawn(), y delay()
Patrones de código comúnmente afectados
Con eventos remotos, los siguientes ejemplos dejan de funcionar correctamente o tienen un comportamiento sutilmente diferente; dependen de que los eventos se reanuden de inmediato.
Activar y capturar eventos durante la ejecución
En este ejemplo, false siempre se devuelve cuando se habilitan los eventos diferidos porque la llamada de retorno no se ha ejecutado. Para funcionar correctamente, el hilo debe ceder hasta al menos el momento en que el evento debería haberse activado.
local success = false
event:Connect(function ()
success = true
end)
doSomethingToTriggerEvent() -- Hace que se active `event`
return success
Escuchar la primera ocurrencia de un evento
connection = event:Connect(function ()
connection:Disconnect()
-- hacer algo
end)
Con los eventos diferidos habilitados, múltiples invocaciones de controladores de eventos pueden estar en cola antes de que te desconectes del evento. Llamar a Disconnect() elimina todas las invocaciones pendientes de controladores de eventos; el mismo comportamiento que existe para eventos inmediatos.
Alternativamente, usa Once() como un método más conveniente para conectar a un evento del que solo necesitas la primera invocación.
Eventos que cambian la ascendencia o propiedades
Los eventos diferidos hacen que los eventos que manejan un cambio en la ascendencia o una propiedad se activen después de que la ascendencia o propiedad haya cambiado:
local part = Instance.new("Part", workspace)
local function onPartDestroying()
print("En señal:", part:GetFullName(), #part:GetChildren())
end
part.Destroying:Connect(onPartDestroying)
part:Destroy()
Debido a que Destroy() funciona de inmediato después de que el script que lo llamó cede, la instancia ya ha sido destruida para cuando se llama a onPartDestroying(). Para más ejemplos, consulta Instance.Destroying.