慣性聚合 関心のあるブログ、ニュース、テクノロジーを効率的に追跡
原文を読む 慣性聚合で開く

おすすめ購読元

博客园 - 司徒正美
V
V2EX
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
Apple Machine Learning Research
Apple Machine Learning Research
IT之家
IT之家
Blog — PlanetScale
Blog — PlanetScale
A
About on SuperTechFans
月光博客
月光博客
T
The Blog of Author Tim Ferriss
宝玉的分享
宝玉的分享
Martin Fowler
Martin Fowler
博客园 - 聂微东
The GitHub Blog
The GitHub Blog
V
Visual Studio Blog
WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
Engineering at Meta
Engineering at Meta
GbyAI
GbyAI

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
プリティプリントでは十分ではありません。私は実際のテーブルビューを使ったJSON & XMLビューワーを作成しました。
Aleksandre M · 2026-05-24 · via DEV Community

私が試したJSONビューワーはすべて同じことをします:それらはきれいに整形します。インデントを追加し、キーを色付けし、括弧を畳みます。10行の設定には便利ですが、実際に開発者が毎日扱うデータの形状には役立ちません。それはオブジェクトの配列です

。きれいに整形された50行のAPIレスポンスは、まだ500行スクロールしてトップからボトムまで見る必要があります。「管理者のみを表示」라고 말할 수 없습니다。 すべての記録を再読み込みせずに。日付で並べ替えることはできません。行全体で検索することもできません。

それはビューアーの問題ではありません — それは間違った形式です。オブジェクトの配列は テーブル になりたいのです:

┌────┬───────┬───────┬────────┐
│ ID │ NAME  │ ROLE  │ ACTIVE │
├────┼───────┼───────┼────────┤
│ 1  │ Alice │ admin │ ● Yes  │
│ 2  │ Bob   │ user  │ ● Yes  │
│ 3  │ Carol │ user  │ ● No   │
│ 4  │ Dave  │ admin │ ● Yes  │
└────┴───────┴───────┴────────┘

フルスクリーンモードを開始 フルスクリーンモードを終了

並べ替え可能な列。検索可能な行。任意の行をクリックして完全なネストされた詳細を展開します。同じデータ — しかしあなたスキャンそれを使う代わりに読むそれ。

だから私は作りましたprettyjsonxml.com— JSONとXMLビューワーが配列を実際のテーブルに変換(折りたたみ可能なツリービュー、フォーマット、ミニファイ、Base64画像プレビューを含む)。1つのHTMLファイル。バックエンドなし。ビルドステップなし。ブラウザ内で完全に実行;データはあなたのマシンから決して離れません。

思いがけなかったこと:9 MBのAPIレスポンスでテーブルビューが実際に高速になるようにするのは、見た目よりずっと難しい問題だった。ここに編集されていないストーリーがある。

簡単なバージョン:動作する、動かない

V1はシンプルだった:

const data = JSON.parse(text);
renderTable(data);

function renderTable(items) {
  const tbody = document.querySelector('tbody');
  items.forEach(row => {
    const tr = document.createElement('tr');
    // ... build cells
    tbody.appendChild(tr);
  });
}

フルスクリーンモードに入る フルスクリーンモードから退出する

テストした5行の例には美しかった。その後、実際のAPIレスポンスを貼り付けた。ブラウザが1.5秒間フリーズしました

フリーズの原因は2つありました

  1. JSON.parse9 MBのブロックでメインスレッドを約500 ms停止しました
  2. 30,000 × 2行(メイン+詳細)= 60,000のDOMノード作成で別の約1500 msブロックしました

どちらも速くすることはできませんが、UIがフリーズしないようにすることができますです.

フェーズ1:content-visibility: auto — 一行で勝つ

モダンブラウザは、オフスクリーンコンテンツのレイアウトをスキップします。CSSルール:

.data-table tr.row-main {
  content-visibility: auto;
  contain-intrinsic-size: auto 40px;
}

フルスクリーンモードに入る フルスクリーンモードから退出する

content-visibility: autoはブラウザに伝えます:「この要素のレイアウトを計算しないで、スクロールして画面に表示される直まで待って。」 contain-intrinsic-size はプレースホルダーの高さを与え、スクロールバーがまだ完全なドキュメントを表すようにします。

レンダリング時間は変わらず、作業はまだ行われますが、感じられるパフォーマンスが向上しました。ブラウザが最初に表示される部分を描画できるからです。犯罪のように活用されていません。現代のブラウザの約95%で動作します。

フェーズ2:JSON.parseのWeb Workers — 反直感の教訓

次のフリーズはJSON.parseそのものだった。常識的なアプローチ:高価なパース処理をメインスレッドからWeb Workerで切り離す。

const worker = new Worker(URL.createObjectURL(new Blob([`
  self.onmessage = (e) => {
    const parsed = JSON.parse(e.data);
    self.postMessage(parsed);
  };
`], { type: 'application/javascript' })));

worker.postMessage(largeJsonString);
worker.onmessage = (e) => render(e.data);

フルスクリーンモードに入る フルスクリーンモードから退出する

完了。メインスレッドは反応的だ。正しい?

実際にはもっと遅かった。

その理由は:ワーカーがパースされたオブジェクトを送り返す際にpostMessage、メインスレッドは構造的クローンオブジェクトグラフ全体を取得するために、メインスレッド上でも。30,000オブジェクトの配列の場合、そのクローンは300~500ミリ秒かかり、

。それで私は成功して500ミリ秒のJSON.parseをメインスレッドから移し、400ミリ秒の構造的クローンを追加した。合計で100ミリ秒の改善。しかしユーザーはフリーズを感じる。は後、すぐに結果が期待されるボタンをクリックした後に流れでが来ます。

Web Workersは、結果が戻ってくる必要がないCPUバウンドの作業に使います。 95%の作業負荷がパースされたオブジェクトそのものである場合、構造クローンのコストが利益を支配します。

フォーマット/ミニファイ用の作業員を保持しました(出力は文字列で、コピーが安価です)。パース後にレンダリングするフローでは、ほとんど利益がなかったです。本当の修正は他にありました

フェーズ3:バーチャルスクロール — 本当の修正

3万行のテーブルの場合、30,000行をレンダリングしません。ユーザーが見ることができる~50行をレンダリングし、スクロールするときにそれらを交換します

<table>の罠は:あなたはできませんposition: absolute 行(テーブルレイアウトでは許可されていません)。代わりに、スパーサーレイアウトを使用してください:

<table>
  <thead>...</thead>
  <tbody>
    <tr style="height:850px"></tr>   <!-- spacer for rows above viewport -->
    <tr>row 21</tr>
    <tr>row 22</tr>
    ...
    <tr>row 70</tr>
    <tr style="height:1200px"></tr>  <!-- spacer for rows below viewport -->
  </tbody>
</table>

フルスクリーンモードを開始 フルスクリーンモードを終了

スクロールイベントごとに、表示される行を再計算し、それらを交換します:

function onScroll() {
  const tbodyRect = tbody.getBoundingClientRect();
  const viewTop = Math.max(0, -tbodyRect.top);
  const viewBottom = viewTop + scrollContainer.clientHeight;

  const startRow = Math.max(0, Math.floor(viewTop / ROW_HEIGHT) - 10);
  const endRow   = Math.min(items.length, Math.ceil(viewBottom / ROW_HEIGHT) + 10);

  // Remove old visible rows, build new ones from items[startRow..endRow]
  // Adjust spacer heights so scrollbar position stays correct
}

フルスクリーンモードを開始 フルスクリーンモードを終了

3万行のJSON配列では、「タブが完全に反応しない」から「スムーズな60fpsスクロール」に変わります。より控えめなサイズでも——例えば数百行——の利点は、検索とソートがインスタントになることです。なぜなら、それらは今やJavaScript配列上で動作するからです。何千ものDOMノードをたどるのではなく。

20分間失ったバグは:私のバーチャルスクローラーがリスニングしていたwindow.scroll ですが、私のページには body { overflow: hidden }<main> { overflow: auto } がありましたので、window.scroll は決して されませんでした。実際のスクロールイベントは <main> から来ていました。

// Walk up to find the nearest ancestor that actually scrolls
function findScrollContainer(el) {
  let p = el.parentElement;
  while (p && p !== document.body) {
    const oy = getComputedStyle(p).overflowY;
    if ((oy === 'auto' || oy === 'scroll') && p.scrollHeight > p.clientHeight) return p;
    p = p.parentElement;
  }
  return window;
}

Enter fullscreen mode Exit fullscreen mode

常に実行時にスクロールコンテナを解決してください。window であると仮定しないでください。

テキストエリアの罠

予期せぬ凍結がもう一つ:9 MBの文字列を<textarea>.valueに割り当てると、それだけでメインスレッドが~300–500 msブロックされる。ブラウザは折りたたまれた部分のほとんどが下にあるにもかかわらず、テキストコンテンツのレイアウトを計算しなければならない。

修正案:ファイル> 5 MBを超える場合、テキストエリアを空にして、スタイル付きの「ロード状態」パネルを表示する代わりに。

if (file.size > 5 * 1024 * 1024) {
  editor.value = '';
  showLoadedOverlay(file.name, file.size);
} else {
  editor.value = text;
}

フルスクリーンモードに入る フルスクリーンモードを終了

データはまだビューアーにパースされ表示されますが、編集可能なテキストエリアには表示されません。9MBのファイルに対しては、誰も手動で編集したくないのでしょう

もう少し違う方法でやるべきこと

  • バーチャルスクロールから始めるそれをフェーズ3として追加しない。それが唯一スケールするものです。他のすべてはポリッシュです
  • 「Workerに移動する」という反射を疑う ワーカーは不要なバックアップを計算するのに最適です。パース後にクローンするフローには向きません.
  • 適用可能な場所にcontent-visibility: autoを使用してください.基本的に無料です.
  • 本番データで早期にテストしてください.私の5行のテストケースはすべての興味深いバグを隠しました.

単一ファイルのこと

自分自身と議論し続けていたのはビルドステップを追加するかどうかの件。「ただバンドルして、ただモジュールに分けて、ただTypeScriptを追加して…」そのあらゆるプロトタイプは技術的にクリーンで、物質的に悪かった——今はもっとファイルをホストしなければならず、キャッシュバスティングの問題を心配し、ツールチェーンをメンテナンスしなければならなかった.

「100%ブラウザ内で、サーバー不要」というツールの全体の訴求を持ち、それを一つのHTMLファイルとして配信するにはSave Asをオフラインで実行するのが正しい製品の決定です。プラグマを純粋さの上に置きます.

最終版:~225 KBの単一HTML、依存関係なし、ビルド不要、Cloudflare Pagesからそのまま提供.


試してみたい場合は:prettyjsonxml.com — 任意のJSONまたはXMLを貼り付け、ソート可能な表または折りたたみ可能な木として表示します。必要だったから作りました。おそらくあなたも同じように必要かもしれないから共有します。

ビッグデータUIのためのパフォーマンスのテクニックは何を使いましたか?人々を驚かせたものについていつも興味があります。