DEV Community

Sachin Kasana
Sachin Kasana

Posted on • Originally published at javascript.plainenglish.io on

How Web Workers Saved My JavaScript App from Freezing on Every CSV Upload

A real-world performance fix that made my app usable again.

Ever uploaded a file and watched your app turn into a brick?

That’s what was happening in my dashboard app — a CSV visualizer that lets users upload massive spreadsheets, crunch the data, and generate real-time stats + charts.

It was working great… until people started uploading actual real-world CSVs.

  • 1 MB? Fine.
  • 5 MB? Kinda slow.
  • 20 MB? 🧊 Frozen UI. Zero response.

You clicked a button? Nothing.

Tried to scroll? Good luck.

Even the loader stopped spinning because… JavaScript was busy choking.

💡 Where It Went Wrong

JavaScript runs on a single thread.

That means any heavy CPU work (like parsing and summarizing CSV data) blocks everything else — buttons, scroll, animations, even paint.

I tried async/await. I tried debouncing. I tried optimizing my code like a maniac.

But the real problem?

My app was asking the main thread to do everything.

⚙️ What Was Happening Behind the Scenes

Every time a CSV was uploaded, I was doing this:

const reader = new FileReader();
reader.onload = (e) => {
  const text = e.target.result;
  const rows = parseCSV(text); // heavy loop!
  const stats = generateStats(rows); // CPU-heavy
  renderDashboard(stats); // React state update
};
reader.readAsText(file);
Enter fullscreen mode Exit fullscreen mode

Looks simple — but parseCSV and generateStats were brutal on big files.

React choked. The browser hung. The UI stopped responding.

🔥 Enter Web Workers

I needed a way to move all that heavy lifting off the main thread.

That’s where Web Workers come in — basically background threads for JavaScript.

They can’t touch the DOM, but they can do all the grunt work without blocking your UI.

🛠️ Step-by-Step: How I Refactored with Web Workers

📁 Create a worker file

// csvWorker.js
self.onmessage = function (event) {
  const csvText = event.data;
  const rows = parseCSV(csvText); // custom parser
  const stats = generateStats(rows); // summary metrics
  self.postMessage(stats);
};
Enter fullscreen mode Exit fullscreen mode

📥 Send work from your app

// inside App.jsx
const worker = new Worker(new URL('./csvWorker.js', import.meta.url), { type: 'module' });

worker.postMessage(csvText);

worker.onmessage = (e) => {
  const stats = e.data;
  setDashboardData(stats); // back on the main thread
};
Enter fullscreen mode Exit fullscreen mode

Boom. 🎯

The UI no longer froze. The spinner kept spinning. And users could scroll and click freely — even with 30MB CSVs uploading in the background.

🎉 The Results

Before Web Workers:

  • App froze for 3–5 seconds on every upload
  • Some browsers showed “Page is unresponsive” warnings
  • Rage-quits happened

After Web Workers:

  • Smooth, non-blocking experience
  • UI stays interactive while CSV is being parsed
  • Feels like a native desktop app now

🧠 Lessons I Learned

  • Web Workers are wildly underused. Especially for apps that deal with data-heavy processing.
  • They’re not hard to set up. Especially with modern tooling (Vite, Webpack, etc. support importing worker files natively).
  • You can’t share variables between threads. Use postMessage to send and receive data — no shared memory.
  • They work great with React. Just don’t try to touch DOM or React state inside the worker.

🔚 Final Thoughts

If your JavaScript app feels sluggish during file uploads, data crunching, or image processing — don’t blame React.

Blame the main thread.

Then give it a break — and let a Web Worker do the dirty work.

They’re not the most glamorous tool in the toolbox, but they might just save your app from performance hell.

🙌 Enjoyed the post?

If this helped you think differently about performance in JavaScript apps, drop a 👏 or leave a comment — I’d love to hear what you’re building or struggling with!

🧑‍💻 Check out more dev tools & blogs I’m working on:

📁 Portfolio → https://sachinkasana-dev.vercel.app

🔧 JSON Formatter Tool → https://json-formatter-web.vercel.app

Let’s keep making the web faster — one main thread at a time. 🚀

Thank you for being a part of the community

Before you go:


Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (0)

👋 Kindness is contagious

Explore this compelling article, highly praised by the collaborative DEV Community. All developers, whether just starting out or already experienced, are invited to share insights and grow our collective expertise.

A quick “thank you” can lift someone’s spirits—drop your kudos in the comments!

On DEV, sharing experiences sparks innovation and strengthens our connections. If this post resonated with you, a brief note of appreciation goes a long way.

Get Started