Skip to content

fix: 로드가 겹칠 때 늦게 끝난 로드가 새로 열린 문서의 화면·상태를 덮는다 #37

Description

@onetwothr1

배경

main.tsloadUrl/loadSelectedFile로드 세대(epoch) 개념이 없다. 두 로드가 겹치면 늦게 끝난 쪽이 새로 열린 문서의 상태를 그대로 덮어쓴다.

FiguresTab은 같은 문제를 #scanGeneration으로 해결했는데(#34), 문서 로드 경로에는 그에 상응하는 장치가 없다.

재현되는 증상

① 오래된 TOC가 새 문서를 덮는다. 문서 A의 outline 조회가 오래 걸리는 사이 B를 열면, A의 renderToc(...)가 B의 목차를 덮는다.

② 늦게 끝난 로드의 성공 tail이 새 문서 상태를 되돌린다. A의 initializeDocdocData 할당, downloadName, showOnly(readRow), setPageUi(...)가 B가 이미 세팅한 값 위에 덮인다.

③ 늦게 끝난 로드의 실패가 새 문서 위에 오류 화면을 띄운다. A의 tail에서 예외가 나면 A의 catchfiguresTab.setDocument(null) + setError(error)를 실행한다 → B는 정상 로드됐는데 오류 화면이 뜨고, B의 그림·표 탭은 #doc = null이라 영구히 스캔되지 않는다.

범위 메모

②③의 가장 날카로운 트리거였던 getOutlineItems의 미보호 getOutline() 거절은 #35에서 함수 내부 방어(try/catch + 문서 교체 감지)로 막았다. 하지만 그건 한 함수만 막은 것이고, ①②는 그대로 남아 있으며 tail에 await가 추가되면 ③도 되살아난다.

근본 해결은 #scanGeneration과 같은 모양의 로드 epoch다:

let loadEpoch = 0;
async function loadUrl(file: string) {
  const epoch = ++loadEpoch;
  ...
  const doc = await host.loadUrl(file);
  if (epoch !== loadEpoch) return;   // 뒤늦게 끝난 로드는 새 로드를 덮지 않는다
  ...
}

await 뒤 공유 상태를 건드리는 모든 지점과 catch 진입부에 같은 검사가 필요하다.

수용 기준

  • 겹친 로드에서 늦게 끝난 쪽이 docData·downloadName·TOC·표시 상태·figuresTab을 건드리지 않는다.
  • 늦게 끝난 로드의 실패가 오류 화면을 띄우지 않는다.
  • 정상 단일 로드 동작은 불변.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions