Skip to content

perf: async main-process file I/O and debounced log counter#36

Merged
oahsiao merged 1 commit into
mainfrom
perf/async-io-and-debounced-counter
Jun 25, 2026
Merged

perf: async main-process file I/O and debounced log counter#36
oahsiao merged 1 commit into
mainfrom
perf/async-io-and-debounced-counter

Conversation

@oahsiao

@oahsiao oahsiao commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Performance improvements with no behavior or API changes — purely internal. Three hotspots are addressed: blocking file I/O in the main process and an unthrottled counter in the renderer.

Changes

1. Non-blocking file read — fs:readText (src/main/ipc.js)

The viewer's file reader used synchronous fs.statSync / fs.openSync / fs.readSync / fs.closeSync, reading up to 5 MB on the main thread. While a large LOG loads, the main process event loop is frozen, so every window and all IPC stall.

  • Converted to fs.promises (fsp.stat, fsp.open, FileHandle.read, FileHandle.close).
  • The 5 MB cap, binary-detection (NUL probe), truncated flag and the returned object shape are all unchanged.

2. Non-blocking directory listing — fs:list (src/main/ipc.js)

The file-tree listing did a blocking fs.statSync per entry, serializing one syscall after another on large folders.

  • Converted to async fsp.readdir + fsp.stat.
  • Entry stats now run concurrently via Promise.all, so listing a big folder no longer blocks the main process and finishes faster.
  • Per-entry stat failures are still ignored individually; return shape unchanged.

3. Debounced LOG counter — src/renderer/js/app.js

The line/character counter ran on every input event of the LOG textarea, re-splitting the entire buffer with a regex on each keystroke — noticeably laggy when editing or pasting very large logs.

  • Added updateCounterSoon() (150 ms debounce) and wired it to the textarea input handler.
  • Context switches (tab change, language switch, initial render) still call updateCounter() immediately, so the displayed count is always correct when the active LOG changes.

Why

  • Keeps the UI responsive while opening large logs and browsing big output folders.
  • Eliminates per-keystroke work proportional to log size in the editor.

Compatibility / risk

  • Low risk. IPC return shapes are identical, so the renderer needs no changes.
  • No new dependencies; no public API or persisted-data changes.

Validation

  • Verified with the editor language service — no errors in either file.
  • The existing static self-test suite (test/selftest.test.js) covers i18n keys, highlight regex compilation and duplicate ids; it does not touch these code paths, so its behavior is unaffected. Please run npm test in CI / a Node environment to confirm (Node was not available in the dev environment used here).

Files changed

  • src/main/ipc.js — async fs:readText and fs:list
  • src/renderer/js/app.js — debounced counter

Convert fs:readText and fs:list IPC handlers from synchronous fs calls to async fs.promises so reading large logs or listing big folders no longer blocks the main process event loop. fs:list now stats entries concurrently via Promise.all. Return shapes are unchanged, so the renderer needs no updates.

Debounce the LOG line/character counter (150ms) on the textarea input event to avoid re-splitting the whole buffer on every keystroke when editing very large pasted logs. Context switches (tab/language) still update the counter immediately.
@oahsiao oahsiao merged commit 1a868ad into main Jun 25, 2026
5 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.

1 participant