Hey developers! Welcome to my second blog on JavaScript performance.
In this post, Beforing walking you through optimizing long tasks in JavaScript in this post to prevent performance bottlenecks, I recommend reading the previous post Part 1 of performance in Javascript
We'll dive into DevTools' Performance tab to analyze slow-performing functions, identify bottlenecks, and improve execution time effectively.
Let’s explore how to make your JavaScript code more efficient!
In Login/index.tsx file, I have added a long task
function heavyComputation() {
let total = 0;
for (let i = 0; i < 1e9; i++) { // Heavy loop
total += i;
}
console.log("Computation done:", total);
}
useEffect(() => {
heavyComputation(); // UI freezes while processing
console.log("Task complete!")
},[])
On clicking "Event Log" tab, we can see "Function call" and on expanding it, it shows heavyComputation details (Look carefully at right side, index.tsx:203:12 Same you can see on the right side) -> It is showing exact line from where this heavy operation is happening.
Total Time: ~1023ms
Now we can see below 👇, for loop is taking almost 2 sec to complete the operation and it is blocking our main thread.😵💫
🔴 Issues:
- The UI freezes while the computation runs.
- No interactions or rendering updates happen until the task completes.
🟢 Solution:
Create a worker.js file under public folder👇
self.onmessage = () => {
let total = 0;
for (let i = 0; i < 1e9; i++) {
// Heavy computation
total += i;
}
self.postMessage(total); // Send result back
};
Import worker.js and set result in the component whenever it is ready
useEffect(() => {
const worker = new Worker(new URL('./public/worker.js',
import.meta.url));
worker.onmessage = (e) => {
setResult(e.data);
console.log('Task complete!', e.data);
};
worker.postMessage('start'); // Start computation
return () => worker.terminate(); // Cleanup
}, []);
Now, retry performance recording and see the result -
💡 Benefits:
- Total time reduced significantly.
- UI remains responsive (no blocking of the main thread).
- Computation runs in a separate thread, preventing UI freezes.
- Better user experience and faster interactions.
Alternative solution instead of using "worker"? 💡
If Web Workers aren’t an option, we can also chunk the computation to run only during idle time. (Using requestIdleCallback approach)
useEffect(() => {
let total = 0;
let i = 0;
function processChunk(deadline) {
while (i < 1e9 && deadline.timeRemaining() > 0) {
total += i;
i++;
}
if (i < 1e9) {
requestIdleCallback(processChunk);
} else {
console.log('Computation done:', total);
}
}
requestIdleCallback(processChunk);
}, []);
What deadline.timeRemaining means in requestIdleCallback?
deadline.timeRemaining() is a method inside requestIdleCallback that tells us how much time (in milliseconds) is left in the current idle period. It helps split heavy tasks into smaller chunks that run only when the browser is idle, keeping the UI responsive.
✔ Key Takeaways from this blog?
- Use Web Workers for CPU-heavy tasks 🧠
- Use requestIdleCallback for lower-priority tasks ✔️
- Never block the main thread in Javascript/ReactJS! 👍
Comment down your go to solution 👇