Skip to content

perf: remove unnecessary return await and cache import maps in denops/ddx#6

Merged
Shougo merged 3 commits intomainfrom
copilot/performance-improvements-shougo-37
Mar 24, 2026
Merged

perf: remove unnecessary return await and cache import maps in denops/ddx#6
Shougo merged 3 commits intomainfrom
copilot/performance-improvements-shougo-37

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 24, 2026

Two micro-optimisations ported from Shougo/dpp.vim#37 to reduce redundant microtasks and redundant filesystem I/O on every plugin import.

Remove unnecessary return await

Simple tail-call delegations that were needlessly suspending with await:

// before
return await ddx.analyze(denops);   // app.ts
return await this.restart(denops);  // ddx.ts

// after
return ddx.analyze(denops);
return this.restart(denops);

Only pure delegations changed; await inside try/catch blocks is left intact to preserve stack traces.

Cache import maps and importers (utils.ts)

Two module-scope caches keyed by parent directory:

const importMapCache = new Map<string, ImportMap | null>();
const importerCache  = new Map<string, ImportMapImporter>();
  • tryLoadImportMap now hits importMapCache before touching the filesystem; stores null for directories with no import map so the four-pattern probe is skipped on repeat calls.
  • importPlugin reuses a cached ImportMapImporter instance instead of constructing a new one per call; also drops the now-redundant await before importer.import() / import().

Trade-off: import map changes during the process lifetime are not picked up (same as dpp.vim#37).

Original prompt

Two small performance improvements adapted from Shougo/dpp.vim PR #37: remove unnecessary return await and cache import maps/ImportMapImporter at module scope to avoid redundant I/O and instance allocation.

Summary of changes to apply in Shougo/ddx.vim (denops parts):

  1. Remove unnecessary return await
  • Replace simple async wrapper functions that immediately return await someAsync() (and are not inside try/catch used to capture stack) with return someAsync() to avoid an extra microtask. Only change occurrences that are simple delegations; do not change code where await is used inside try/catch to preserve stack behaviour.
  1. Cache import maps and ImportMapImporter in utils.ts
  • Add module-scope caches in denops/ddx/utils.ts:
    • const importMapCache = new Map<string, ImportMap | null>();
    • const importerCache = new Map<string, ImportMapImporter>();
  • Update tryLoadImportMap(script: string) to check importMapCache keyed by parent directory before reading files. Store null for directories without import maps.
  • Update importPlugin(path: string) to reuse cached ImportMapImporter instances from importerCache when an import map exists for the path's parent directory.
  • Keep external API unchanged. Document that import_map changes during process lifetime will not be picked up (same trade-off as dpp.vim PR #37).

Files to change (identified during repository scan):

  • denops/ddx/utils.ts (tryLoadImportMap, importPlugin)
  • denops/ddx/app.ts (RPC handlers like start, restart, redraw, uiAction, analyze, jump, getDiff — remove simple return await wrappers where safe)
  • denops/ddx/loader.ts (ensure importPlugin reuse; remove redundant wrappers)
  • denops/ddx/ddx.ts (methods like start, restart, redraw, uiUpdateCursor — adjust simple await returns where safe)

Commit strategy:

  • Commit 1: Remove unnecessary return await only.
  • Commit 2: Add import map + importer caches in utils.ts and update importPlugin/tryLoadImportMap to use caches.

Testing and validation:

  • Run repository tests (if any): deno test -A --doc --parallel --shuffle denops/**/*.ts.
  • Manual smoke check: load plugin and exercise typical API flows to confirm imports and API calls behave as before.

PR title suggestion:
perf: remove unnecessary return await and cache import maps in denops/ddx

Notes:

  • The change intentionally trades live import_map reloads for reduced runtime I/O, matching the change in dpp.vim PR #37.
  • Leave try/catch-wrapped await usages untouched to preserve stack traces.

Please run CI/tests and review; I can follow up with fixes if any issues are found.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: Shougo/dpp.vim#37

こちらと同様の修正を ddu.vim, ddc.vim, ddx.vim, ddt.vim に適用させることは可能ですか。

Assistant: 確認して、dpp.vim の PR #37 の内容を取得します。変更点を見て、同じ修正を ddu.vim, ddc.vim, ddx.vim, ddt.vim に適用するための差分を作成します。まず PR の内容を読み取ります。

Assistant: はい、可能です。やるべき変更は dpp.vim の PR #37 と同じで、主に次の2点です。

  1. 不要な return await の削除(マイクロタスクの削減)
  2. import-map のプロセス内キャッシュ化(tryLoadImportMap/importPlugin での import map と ImportMapImporter のキャッシュ)

やり方と現状の確認(私が行ったこと)

  • PR #37 の内容を確認しました(perf: remove unnecessary return await and cache import maps in denops/dpp)。

  • ddu.vim / ddc.vim / ddx.vim / ddt.vim のソースを走査して、return await と import-map 処理の該当箇所を探しました。該当ファイルの候補は以下です。

    • ddu.vim
      • denops/ddu/utils.ts(tryLoadImportMap, importPlugin)
      • denops/ddu/app.ts(dispatcher の uiVisible / uiWinids / uiUpdateCursor 等で return awaitawait の単純返却がある)
      • denops/ddu/loader.ts(importPlugin を呼んでいる箇所)
      • denops/ddu/ddu.ts(ui.* の呼び出しを await でそのまま返している箇所)
    • ddc.vim
      • denops/ddc/utils.ts(tryLoadImportMap, importPlugin, callCallback 等)
      • denops/ddc/ext.ts(return await を使っている例が複数)
      • denops/ddc/app.ts(API 関数内の await の扱い)
      • denops/ddc/loader.ts(importPlugin を呼んでいる箇所)
    • ddx.vim
      • denops/ddx/utils.ts(tryLoadImportMap, importPlugin)
      • denops/ddx/app.ts(API 関数に return await がある箇所)
      • denops/ddx/loader.ts(importPlugin を呼んでいる箇所)
    • ddt.vim
      • denops/ddt/utils.ts(tryLoadImportMap, importPlugin)
      • denops/ddt/app.ts(API の実装で await をそのまま返している箇所)
      • denops/ddt/loader.ts(importPlugin を呼んでいる箇所)
  • 上記ファイル群は PR #37 と同じパターン(tryLoadImportMap/importPlugin の実装がほぼ同様、単純に別関数の Promise を await して返している箇所がある)でした。

想定する修正内容(リポジトリ毎に同様)

  • utils.ts にモジュールスコープで
    • const importMapCache = new Map<string, ImportMap | null>();
    • const importerCache = new Map<string, ImportMapImporter>();
  • tryLoadImportMap(script):
    • parentDir をキーに importMapCache を先にチェックし、ヒットあれば即返却(null をキャッシュして「なし」を表現)。
    • 未ヒットなら既存の探索/読み込みを実行して結果をキャッシュする。
  • importPlugin(path):
    • tryLoadImportMap の結果を使い、importMap がある場合は importerCache を参照して ImportMapImporter を再利用。なければ新規作成してキャッシュ。
    • import するときに return await になっている単純ラッパーは return ... に置換(try/catch 等でスタック取り扱いに差が出る箇所は除外)。
  • return await 削除は try/catch によるスタック保持が不要な単純返却箇所のみ行う(PR #37 と同様の安全方針)。

安全性と注意点

  • 仕様の外部公...

This pull request was created from Copilot chat.


💬 Send tasks to Copilot coding agent from Slack and Teams to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copilot AI changed the title [WIP] Optimize performance by caching imports and removing unnecessary awaits perf: remove unnecessary return await and cache import maps in denops/ddx Mar 24, 2026
Copilot AI requested a review from Shougo March 24, 2026 23:56
@Shougo Shougo marked this pull request as ready for review March 24, 2026 23:56
@Shougo Shougo merged commit 8ba78ce into main Mar 24, 2026
3 checks passed
@Shougo Shougo deleted the copilot/performance-improvements-shougo-37 branch March 24, 2026 23:59
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