<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adrian</title>
    <description>The latest articles on DEV Community by Adrian (@elvingts).</description>
    <link>https://dev.to/elvingts</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4114157%2F39809338-f0c3-4189-b8f5-de604e2e7466.png</url>
      <title>DEV Community: Adrian</title>
      <link>https://dev.to/elvingts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/elvingts"/>
    <language>en</language>
    <item>
      <title>Why parsing a 10MB JSON payload freezes your UI thread (and how to offload it to Web Workers)</title>
      <dc:creator>Adrian</dc:creator>
      <pubDate>Mon, 07 Sep 2026 14:51:10 +0000</pubDate>
      <link>https://dev.to/elvingts/why-parsing-a-10mb-json-payload-freezes-your-ui-thread-and-how-to-offload-it-to-web-workers-3e4k</link>
      <guid>https://dev.to/elvingts/why-parsing-a-10mb-json-payload-freezes-your-ui-thread-and-how-to-offload-it-to-web-workers-3e4k</guid>
      <description>&lt;p&gt;If you have ever built a dashboard or data analysis tool in JavaScript, you have probably run into this scenario: your app fetches a large JSON payload (say, 5MB to 20MB of raw records), runs &lt;code&gt;JSON.parse(data)&lt;/code&gt;, and for 300ms to 1.5 seconds, the entire browser tab completely freezes.&lt;/p&gt;

&lt;p&gt;Buttons don't click. CSS animations drop to 0 FPS. The browser might even throw an &lt;em&gt;"Unresponsive Script"&lt;/em&gt; warning.&lt;/p&gt;

&lt;p&gt;Here is why that happens, why most developers handle it wrong, and how to offload heavy JSON operations to native Web Workers with zero external libraries.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Problem: JavaScript is Single-Threaded
&lt;/h3&gt;

&lt;p&gt;The browser executes your JavaScript, layout calculations, and UI rendering on a &lt;strong&gt;single main thread&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you execute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hugeRawString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main thread cannot paint a single frame or respond to user inputs until &lt;code&gt;JSON.parse&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; have completely finished traversing the entire object graph.&lt;/p&gt;

&lt;p&gt;Even on modern M-series or high-end x86 CPUs, parsing a 15MB JSON file can take 400ms+. On mobile devices, it can easily take 2-4 seconds.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Bad Fix: &lt;code&gt;setTimeout&lt;/code&gt; or &lt;code&gt;async/await&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A common misconception is that wrapping &lt;code&gt;JSON.parse&lt;/code&gt; in a &lt;code&gt;Promise&lt;/code&gt; or &lt;code&gt;setTimeout&lt;/code&gt; makes it non-blocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ THIS STILL BLOCKS THE UI THREAD!&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseDataAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While &lt;code&gt;setTimeout&lt;/code&gt; pushes the task to the next event loop tick, the moment that task executes, &lt;code&gt;JSON.parse&lt;/code&gt; &lt;strong&gt;still runs synchronously on the main thread&lt;/strong&gt;, locking the UI for the exact same amount of time.&lt;/p&gt;




&lt;h3&gt;
  
  
  The Clean Solution: Inline Web Worker Dispatch
&lt;/h3&gt;

&lt;p&gt;Instead of adding a 50KB npm package, you can spawn an isolated Web Worker using a &lt;code&gt;Blob&lt;/code&gt; and &lt;code&gt;URL.createObjectURL&lt;/code&gt;. This runs in a separate OS thread without needing a separate hosted worker file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parseJsonInWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workerCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
      self.onmessage = function(e) {
        try {
          const parsed = JSON.parse(e.data);
          self.postMessage({ success: true, data: parsed });
        } catch (err) {
          self.postMessage({ success: false, error: err.message });
        }
      };
    `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;blob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;workerCode&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;workerUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Worker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workerUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;cleanup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;revokeObjectURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;workerUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jsonString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Benchmarks &amp;amp; Real-World Impact
&lt;/h3&gt;

&lt;p&gt;In our tests processing a 12.4 MB mock database export (approx 85,000 nested JSON objects):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Main Thread &lt;code&gt;JSON.parse&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Web Worker Pipeline&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Main Thread Lock Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;680 ms (UI Frozen)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 ms (60 FPS Constant)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total Computation Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~710 ms&lt;/td&gt;
&lt;td&gt;~740 ms (incl. message clone)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Experience&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Page stutter / freeze&lt;/td&gt;
&lt;td&gt;Smooth progress spinner&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Although the total CPU time is slightly higher due to structured cloning across thread boundaries, the &lt;strong&gt;Main Thread stays completely responsive&lt;/strong&gt;. Input sliders, cancel buttons, and loading animations continue to render at 60 FPS.&lt;/p&gt;




&lt;h3&gt;
  
  
  Where to Use This Architecture
&lt;/h3&gt;

&lt;p&gt;This exact worker pattern is what powers the client-side JSON parser, YAML validator, and Diff engine inside &lt;a href="https://omnitools-pro.surge.sh" rel="noopener noreferrer"&gt;OmniTools Pro&lt;/a&gt;. Even when diffing two massive files, the UI never stutters because computation happens entirely in background threads.&lt;/p&gt;

&lt;p&gt;Have you tackled large JSON bottlenecks in your frontend apps? What's your go-to strategy? Let's discuss in the comments below!&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Why your JSON and Regex tools shouldn't send data to a backend (and how I built a zero-leak client suite)</title>
      <dc:creator>Adrian</dc:creator>
      <pubDate>Mon, 07 Sep 2026 14:44:54 +0000</pubDate>
      <link>https://dev.to/elvingts/why-your-json-and-regex-tools-shouldnt-send-data-to-a-backend-and-how-i-built-a-zero-leak-client-c3a</link>
      <guid>https://dev.to/elvingts/why-your-json-and-regex-tools-shouldnt-send-data-to-a-backend-and-how-i-built-a-zero-leak-client-c3a</guid>
      <description>&lt;p&gt;Every developer does it at least once a week: you get an unformatted 2MB payload from an internal endpoint or a complex regex string from a colleague, and you throw it into an online web formatter or tester.&lt;/p&gt;

&lt;p&gt;The problem? Most top search results for "JSON formatter" or "JWT debugger" are laden with heavy ad trackers, telemetry pixels, and in several cases, quietly transmit the pasted text back to an external server. If that payload contains authorization headers, customer PII, API secrets, or internal database IDs, you have just unknowingly leaked confidential data.&lt;/p&gt;

&lt;p&gt;I got tired of worrying about this, so I built &lt;a href="https://omnitools-pro.surge.sh" rel="noopener noreferrer"&gt;&lt;strong&gt;OmniTools Pro&lt;/strong&gt;&lt;/a&gt; — a suite of 16 developer utilities that runs 100% inside your browser with zero backend data transmission.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works (and why the architecture matters)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero Server Footprint for Processing:&lt;/strong&gt;&lt;br&gt;
All operations—JSON parsing, YAML conversions, JWT decoding, UUID generation, Diff comparisons, and SHA/MD5 hashing—execute inside local Web Workers and standard Web APIs (&lt;code&gt;crypto.subtle&lt;/code&gt;, &lt;code&gt;JSON.parse&lt;/code&gt;). If you open your browser DevTools Network tab while using the tool, you will see zero outgoing POST requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Offline-First PWA:&lt;/strong&gt;&lt;br&gt;
The entire site is cached via a lightweight Service Worker. Once loaded once, you can turn off your Wi-Fi and format or diff code completely offline.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Sub-second Load Times:&lt;/strong&gt;&lt;br&gt;
Zero heavy frameworks, zero third-party tracking scripts. Pure vanilla HTML, modular JS, and clean CSS running on Global Edge CDN.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Live Demo &amp;amp; Feedback
&lt;/h3&gt;

&lt;p&gt;You can test it out live here: &lt;strong&gt;&lt;a href="https://omnitools-pro.surge.sh" rel="noopener noreferrer"&gt;https://omnitools-pro.surge.sh&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built this primarily to solve my own workflow friction, but I hope it saves other developers time and eliminates unnecessary privacy risks. If you run into edge cases or want additional offline utilities added, let me know in the comments!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
