Skip to content

perf(desktop): reuse one collator for sidebar natural sort - #6039

Merged
Jocs merged 1 commit into
marktext:developfrom
b84330808:perf-sidebar-natural-compare
Nov 13, 2026
Merged

Jocs merged 1 commit into
marktext:developfrom
b84330808:perf-sidebar-natural-compare

Conversation

@b84330808

@b84330808 b84330808 commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Related to #3893

Summary

Opening a folder with many files is slow (see #3893). One reason is in the sidebar's natural sort: naturalCompare() in treeCtrl.ts called a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) for every comparison. Passing an options object makes localeCompare construct a new Intl.Collator on every call (~6 µs each, vs ~0.3 µs for a comparison through a shared collator), and the sorted inserts in addDirectory()/addFile() run it once per sibling for every node, so opening a large folder builds collators quadratically.

This change hoists a single Intl.Collator with the same (default) locale and the same options to module scope and compares through it. Per ECMA-402 the ordering is identical to the previous localeCompare calls, so the sort result does not change.

Measurements (Windows, replaying add/addDir events into the real treeCtrl with a Vue reactive tree, 3 alternating rounds; renderer only, disk I/O excluded):

  • mdn/content (14,758 md files, ~14.7k folders), default sort: 12.0 s → 3.5 s
  • mdn/content, sort by title: 11.8 s → 3.3 s
  • rust-lang/rfcs (653 md files), sort by title: 1.37 s → 0.14 s

Also verified end-to-end on Linux (Xvfb, production build, the same mdn/content clone, GUI flow from app launch until the sidebar's "Loading folder..." indicator disappears): ~36.5 s → ~28.5 s, single runs. That flow also includes app startup and the main-process directory walk (~24 s in both runs), so the renderer-side difference (~8 s) lines up with the Windows numbers.

Screen recordings (Linux, end-to-end)

Before (develop, a520bef):

marktext-before.mp4

After (this branch):

marktext-after.mp4

Type of change

  • Bug fix (non-breaking, fixes an issue)
  • New feature (non-breaking, adds functionality)
  • Breaking change (causes existing functionality to change)
  • Documentation update

Test plan

  • New tests added (or explain why not needed) — no new tests: the change is behavior-preserving by construction (same locale, same options, spec-equivalent ordering) and the existing sidebar/project suites cover the tree. On Linux, 15 sidebar/project unit spec files (100 tests) pass and ESLint passes on the changed file; on Windows, the sidebar and project-store specs (9 files, 57 tests) pass as well.
  • Manually tested on: Linux

Notes for reviewers [optional]

This code was written by an AI assistant; I have read it, tested it as described above, and can answer questions about it. The change is intentionally minimal: one shared collator instead of one per comparison.


By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.

naturalCompare() called localeCompare() with options, which creates a new
Intl.Collator on every call. Sorted inserts into the sidebar tree call it
once per sibling, so opening a folder with many entries spent most of its
renderer time constructing collators. A shared Intl.Collator with the same
locale and options gives the same ordering.

@Jocs Jocs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the shared collator change. Local validation passed: 100 sidebar/project unit tests, lint, typecheck, and production builds. Verified the real Electron app on macOS with 10,001 Markdown files: natural ordering and file opening work, with lower folder loading time. This is a scoped performance improvement; it does not establish that all symptoms of #3893 are fixed.

@Jocs
Jocs merged commit d083522 into marktext:develop Nov 13, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants