Workspace.SignalBehavior 속성은 이벤트 핸들러가 즉시 실행될지 아니면 지연될지를 제어합니다. Enum.SignalBehavior.Deferred 옵션이 추천되며, 이는 엔진의 성능과 정확성을 향상시키는 데 도움이 됩니다. 지연 이벤트에 대한 이벤트 핸들러는 다음 복원 지점에서 최근에 트리거된 이벤트 핸들러와 함께 재개됩니다.
다음 다이어그램은 Immediate 이벤트 동작과 Deferred 이벤트 동작을 비교합니다.
- Immediate 동작에서는 한 이벤트가 다른 이벤트를 트리거하면 두 번째 이벤트 핸들러가 즉시 실행됩니다.
- Deferred 동작에서는 두 번째 이벤트가 큐의 뒤에 추가되고 나중에 실행됩니다.
소요되는 총 시간은 변경되지 않지만, 순서는 다릅니다.

"재진입성"은 이벤트가 특정 깊이에 도달했을 때 서로 계속해서 실행되는 것을 방지합니다. 현재 이 한계는 10입니다.
지연 이벤트의 이점
Immediate 동작은 몇 가지 단점이 있습니다. 게임에 추가되는 각 인스턴스, 변경되는 속성 또는 어떤 다른 트리거가 호출될 때마다 엔진은 다른 작업이 발생하기 전에 Luau 코드를 실행해야 합니다.
- 1,000개의 속성을 변경하려면 각 변경 후에 1,000개의 코드 조각이 실행될 가능성이 있습니다.
- 이상하고 진단하기 힘든 버그가 발생할 수 있습니다. 예를 들어, 어떤 것이 추가되기 전에 제거 이벤트가 실행되는 경우입니다.
- 성능이 중요한 시스템은 이벤트를 실행하면서 Luau와 주기적으로 양방향으로 작업을 yield해야 합니다.
- 이벤트 핸들러는 이벤트가 실행될 때마다 장소를 변경하거나 다른 이벤트를 트리거할 수 있습니다.
- 이벤트는 중복에도 불구하고 여러 번 실행될 수 있습니다. 예를 들어, 속성이 두 번 변경되는 경우입니다.
Luau가 실행될 수 있는 엔진 생명 주기의 특정 부분을 가짐으로써, 엔진은 몇 가지 가정을 사용하여 성능을 개선할 수 있습니다:
- 성능이 중요한 시스템은 Luau에 yield할 필요가 없으며, 이는 성능 향상으로 이어집니다.
- 엔진 자체가 변경하지 않는 한, 장소는 복원 지점 외부에서는 절대 변경되지 않습니다.
복원 지점
지연된 후, 이벤트 핸들러는 다음 복원 지점에서 재개됩니다. 현재 설정된 복원 지점의 집합은 다음과 같습니다:
- 입력 처리 (처리가 필요한 입력당 한 번 재개됨, UserInputService 참조)
- wait(), spawn(), delay()와 같은 레거시 대기 스크립트 복원
일반적으로 영향을 받는 코드 패턴
원격 이벤트와 함께, 다음 예제는 올바르게 작동하지 않거나 미세하게 다른 동작을 하며, 이벤트가 즉시 재개되는 것에 의존합니다.
실행 중간 이벤트를 트리거하고 포착하기
이 예제에서는 지연 이벤트가 활성화되면 항상 false가 반환됩니다. 이는 콜백이 아직 실행되지 않기 때문입니다. 올바르게 작동하려면 스레드가 이벤트가 실행될 시점까지 yield해야 합니다.
local success = false
event:Connect(function ()
success = true
end)
doSomethingToTriggerEvent() -- `event`를 트리거합니다
return success
이벤트의 첫 번째 발생을 청취하기
connection = event:Connect(function ()
connection:Disconnect()
-- 무언가를 수행합니다
end)
지연 이벤트가 활성화된 경우, 여러 이벤트 핸들러 호출이 큐에 추가될 수 있기 때문에 이벤트에서 연결 해제하기 전에 연결 해제를 수행합니다. Disconnect()를 호출하면 모든 대기 중인 이벤트 핸들러 호출이 삭제됩니다. 이는 즉시 이벤트에 대한 동일한 동작을 수행합니다.
또는 Once()를 사용하여 첫 번째 호출만 필요한 이벤트에 보다 편리하게 연결할 수 있습니다.
조상이나 속성을 변경하는 이벤트
지연 이벤트는 조상이나 속성의 변경을 처리하는 이벤트가 조상이나 속성이 변경된 후에 실행되도록 합니다:
local part = Instance.new("Part", workspace)
local function onPartDestroying()
print("신호 내:", part:GetFullName(), #part:GetChildren())
end
part.Destroying:Connect(onPartDestroying)
part:Destroy()
Destroy()가 이를 호출한 스크립트가 yield된 후 즉시 작동하기 때문에 onPartDestroying()이 호출되기 전에 인스턴스는 이미 파괴됩니다. 더 많은 예제는 Instance.Destroying을 참조하십시오.