본문으로 건너뛰기

[Open WebUI] UserMessage에서 JSON 직렬화 대신 structuredClone과 빠른 경로 비교 적용

PR 링크: open-webui/open-webui#22098 상태: Merged | 변경: +8 / -3

들어가며

Svelte의 반응형 시스템에서 객체 변경 감지는 성능에 직접적인 영향을 미친다. Open WebUI의 UserMessage 컴포넌트는 히스토리에서 메시지 객체를 복사하고, 변경 여부를 JSON.stringify 비교로 판단한 후 재복사하는 패턴을 사용하고 있었다. 이 과정에서 JSON.parse(JSON.stringify()) 깊은 복사와 매 반응형 업데이트마다 전체 객체 직렬화가 발생했다.

핵심 코드 분석

Before: JSON 직렬화 기반 복사와 비교

let message = JSON.parse(JSON.stringify(history.messages[messageId]));
$: if (history.messages) {
    if (JSON.stringify(message) !== JSON.stringify(history.messages[messageId])) {
        message = JSON.parse(JSON.stringify(history.messages[messageId]));
    }
}

After: structuredClone + O(1) 빠른 경로

let message = structuredClone(history.messages[messageId]);
$: if (history.messages) {
    const source = history.messages[messageId];
    if (source) {
        if (message.content !== source.content) {
            message = structuredClone(source);
        } else if (JSON.stringify(message) !== JSON.stringify(source)) {
            message = structuredClone(source);
        }
    }
}

왜 이게 좋은가

  1. structuredClone 사용: JSON.parse(JSON.stringify())undefined, Date, RegExp 등을 올바르게 처리하지 못한다. structuredClone은 브라우저 네이티브 API로 더 정확하고 빠른 깊은 복사를 제공한다.
  2. O(1) 빠른 경로 비교: 대부분의 메시지 변경은 content 필드 변경이다. 문자열 비교는 O(n)이지만, 전체 객체를 JSON으로 직렬화하는 것보다 훨씬 가볍다. content가 같을 때만 전체 비교로 폴백한다.
  3. null 안전성: source 존재 여부를 먼저 확인하여 삭제된 메시지에 대한 에러를 방지한다.

채팅 중 history.messages가 변경될 때마다 이 비교가 실행되므로, 빠른 경로로 대부분의 불필요한 직렬화를 건너뛸 수 있다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글