perf: 화면 진입 중복 호출 정리 — 세션·워크플로 상태·구조물 이관
실측(B05 진입): auth/session 4회, workflow-state 2회, 구조물 이관 POST 가 진입할 때마다 나갔다. - auth/session: 라우터 가드·상단 바·워크플로 확인이 각각 부르던 것을 5초 캐시로 묶음. 로그인·로그아웃에서 즉시 버린다. - workflow-state: 공용 창구 하나로 모으고 같은 방식으로 캐시. 상단 오버레이가 따로 부르던 경로를 그 창구로 돌림. 단계 이동에서 캐시를 버린다. - 구 구조물 측점 이관 POST: 탭 수명 동안 노선마다 한 번만. 실측 결과: B05 첫 진입 20 → 18건(핵심 API 10건), B06→B05 이동 7건. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,15 +30,39 @@ export const WORKFLOW_STEP_ROUTES: readonly RoutePath[] = [
|
||||
ROUTES.B09_ESTIMATION,
|
||||
];
|
||||
|
||||
/* 워크플로 상태는 한 화면을 여는 동안 준비 화면 가드와 페이지 본체가 각각 부른다 —
|
||||
실측 B05 진입에서 두 번 나갔다(2026-09-06). 짧은 시간 동안 한 번만 부르고 나눠 쓴다.
|
||||
단계가 바뀌는 자리(`goToWorkflowStage`)에서는 즉시 버린다. */
|
||||
const WORKFLOW_CACHE_MS = 5000;
|
||||
let workflowCache: { at: number; projectId: string; value: Promise<WorkflowState> } | null = null;
|
||||
|
||||
/** 워크플로 상태 캐시를 버린다 — 단계가 바뀌는 자리에서 부른다. */
|
||||
export function clearWorkflowStateCache(): void {
|
||||
workflowCache = null;
|
||||
}
|
||||
|
||||
export async function fetchWorkflowState(projectId: string): Promise<WorkflowState> {
|
||||
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/workflow-state`, {
|
||||
credentials: "include",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Workflow state request failed: ${response.status}`);
|
||||
const now = Date.now();
|
||||
if (
|
||||
workflowCache &&
|
||||
workflowCache.projectId === projectId &&
|
||||
now - workflowCache.at < WORKFLOW_CACHE_MS
|
||||
) {
|
||||
return workflowCache.value;
|
||||
}
|
||||
const data = await response.json();
|
||||
return data.workflow_state ?? data;
|
||||
const value = (async (): Promise<WorkflowState> => {
|
||||
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/workflow-state`, {
|
||||
credentials: "include",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Workflow state request failed: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data.workflow_state ?? data;
|
||||
})();
|
||||
workflowCache = { at: now, projectId, value };
|
||||
value.catch(() => clearWorkflowStateCache());
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,6 +76,8 @@ const PRELOAD_REQUIRED_ROUTES: readonly RoutePath[] = [ROUTES.B04_PREPROCESS, RO
|
||||
|
||||
export function goToWorkflowStage(projectId: string, route: RoutePath): void {
|
||||
localStorage.setItem(CURRENT_PROJECT_ID_KEY, projectId);
|
||||
// 단계가 바뀌어 이동하는 자리다 — 캐시를 버려 다음 화면이 새 상태를 본다.
|
||||
clearWorkflowStateCache();
|
||||
if (!PRELOAD_REQUIRED_ROUTES.includes(route)) {
|
||||
navigateTo(route);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user