When a page freezes, the code that would normally report the freeze is usually frozen with it. Error reporters, metric beacons and dashboard timers run on the same main thread as the interface, so a long synchronous task can stop them from running at all. The result is a dashboard that looks healthy because nothing arrived, not because nothing went wrong.
A Web Worker can close that gap. It can run a timer on its own thread, ask the page to answer a small message, and report a suspected unresponsive main thread when the answer is overdue. That is an engineering pattern built from standard worker messaging and browser scheduling, not a built-in browser feature that detects freezes. It also tells you less than it seems to. A missed reply shows that the page did not handle a message in time. It does not prove a crash, and it does not explain why.
As an Amazon Associate I earn from qualifying purchases.
Why monitoring goes silent during a freeze
Browsers run page JavaScript on the main thread, and the same thread handles event handling and document updates. MDN’s documentation on background tasks describes the main thread’s event-loop duties and the lag that appears when work piles up on it. MDN’s “How browsers work: Interactivity” explains the same mechanism from the rendering side: while a long task runs, the browser cannot promptly process input or repaint.
Free tools Windows power users keep installed
One-click scans. No signup required.
That has a direct consequence for monitoring. A monitor written as ordinary page JavaScript is queued behind the work that is freezing the page. Three common failure patterns follow:
#1 Best Overall
- Kaisi 20 pcs opening pry tools kit for smart phone,laptop,computer tablet,electronics, apple watch, iPad, iPod, Macbook, computer, LCD screen, battery and more disassembly and repair
- Professional grade stainless steel construction spudger tool kit ensures repeated use
- Includes 7 plastic nylon pry tools and 2 steel pry tools, two ESD tweezers
- Includes 1 protective film tools and three screwdriver, 1 magic cloth,cleaning cloths are great for cleaning the screen of mobile phone and laptop after replacement.
- Easy to replacement the screen cover, fit for any plastic cover case such as smartphone / tablets etc
- Error reports never send. The handler that would catch the exception or stall cannot run until the task finishes.
- Periodic metrics show a gap, not a spike. A missing data point looks like low traffic or a quiet period unless someone checks for absence.
- Aggregates average the stall away. A ten-second freeze inside a five-minute reporting window can disappear into averages that are otherwise normal.
A watchdog has to live somewhere the stalled task cannot block. A Web Worker is that place.
What a Web Worker changes
MDN’s Web Workers API documentation states: “Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application.” The worker communicates with the page through messages. It cannot manipulate the DOM, so it cannot see what the interface looks like. It can only send and receive messages and run its own timers.
That limitation is useful. The worker’s clock keeps running while the page is busy, and the only way the page can respond is by processing a message, which it can do only when its main thread is free. The worker therefore measures something concrete: how long the page took to handle a message it was sent.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsRank #2
- Used Book in Good Condition
The heartbeat cycle, step by step
The pattern works as a repeating ping and pong with a deadline:
- Start the worker. The page creates a dedicated worker with
new Worker('heartbeat-worker.js')at application start. - Ping on an interval. The worker’s
setIntervalposts apingmessage with a sequence number and records when it was sent. - Reply on the main thread. The page’s
onmessagehandler posts apongback immediately. Keep this handler tiny, because its only job is to prove the main thread reached it. - Clear the pending ping. When a matching
pongarrives, the worker clears the outstanding ping. - Flag an overdue ping. If a ping is still unanswered after the threshold, the worker posts
suspected-stallto the page with the elapsed time. - Report recovery. When a pong finally arrives after a flagged stall, the worker posts
recoveredso that the stall has an end time.
Implementation
The following code is a minimal, illustrative version. The interval and threshold values are examples only; they are not validated defaults, and you should choose them against the behavior of your own application.
Worker script (heartbeat-worker.js)
const INTERVAL_MS = 1000; // how often to ping (example value)nconst TIMEOUT_MS = 4000; // how long a pong may be overdue (example value)nnlet seq = 0;nlet outstanding = null; // { seq, sentAt } while a pong is pendingnlet reportedStall = false;nnsetInterval(() => {n const now = Date.now();n if (outstanding === null) {n seq += 1;n outstanding = { seq, sentAt: now };n postMessage({ type: 'ping', seq });n return;n }n if (!reportedStall && now - outstanding.sentAt > TIMEOUT_MS) {n reportedStall = true;n postMessage({n type: 'suspected-stall',n seq: outstanding.seq,n elapsedMs: now - outstanding.sentAtn });n }n}, INTERVAL_MS);nnonmessage = (event) => {n const msg = event.data;n if (msg.type !== 'pong' || outstanding === null || msg.seq !== outstanding.seq) return;n if (reportedStall) {n postMessage({n type: 'recovered',n seq: msg.seq,n elapsedMs: Date.now() - outstanding.sentAtn });n reportedStall = false;n }n outstanding = null;n};
Note the arrow functions: the => in the worker’s onmessage assignment is the standard arrow syntax, written with HTML escapes here.
Rank #3
- Used Book in Good Condition
Page script
const worker = new Worker('heartbeat-worker.js');nnworker.onmessage = (event) => {n const msg = event.data;n if (msg.type === 'ping') {n worker.postMessage({ type: 'pong', seq: msg.seq });n } else if (msg.type === 'suspected-stall') {n report('suspected-unresponsive-main-thread', msg);n } else if (msg.type === 'recovered') {n report('main-thread-responding-again', msg);n }n};
The report function should record the event and its context. Do not send it through the same code path that is being monitored unless you accept that it may be delayed, and do not rely on it alone for a stall that never ends; a page that is fully stuck may never send the recovered event.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Record visibility with every event
Attach the document’s visibility state to each report, and keep a timestamp of the last visibility change so the event can be read in context:
let lastVisibilityChange = Date.now();ndocument.addEventListener('visibilitychange', () => {n lastVisibilityChange = Date.now();n});nnfunction report(kind, detail) {n const context = {n kind,n ...detail,n visibilityState: document.visibilityState,n msSinceVisibilityChange: Date.now() - lastVisibilityChange,n reportedAt: new Date().toISOString()n };n // send context to your telemetry endpoint or log it locallyn}
What a missed heartbeat establishes and what it does not
A suspected-stall event establishes one narrow fact: during the interval shown, the page did not handle a message the worker sent within the threshold you configured. That is worth knowing, but it is an indirect signal.
- It does not establish a crash. The page may have been busy, slow, or in a long but finite task that completed later.
- It does not identify the cause. A missed reply does not say which function, component, or network call held the thread.
- It does not establish that the user saw a freeze. If the tab was hidden, the delay may have no user-visible effect.
- It cannot cover every failure of the worker. If the worker itself is starved or terminated, it cannot send any report, so silence from the worker is ambiguous.
Report the event with the wording the evidence supports, such as “suspected unresponsive main thread,” rather than “crash confirmed.”
Background tabs and throttling
Visibility is the most common source of false alarms. MDN’s Page Visibility API documentation states: “The Page Visibility API provides events you can watch for to know when a document becomes visible or hidden, as well as features to look at the current visibility state of the page.” In practice, that means you can tell whether a delayed heartbeat happened while the user was looking at the page.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Browsers apply scheduling policies to hidden tabs. Timers in background tabs can be throttled, and MDN notes that browsers may stop requestAnimationFrame() callbacks in hidden contexts. A heartbeat driven by main-thread timers can therefore slow down in a background tab for reasons unrelated to a freeze. Treat a stall reported while visibilityState is 'hidden' as a lower-priority signal, and check whether the delay is consistent with throttling before escalating it.
Best Value
- Used Book in Good Condition
The reverse also matters. A stall that begins in the foreground and continues after the user switches away is still a stall. Use the visibility-change timestamp to split the interval at the point where the state changed, rather than discarding the event.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Pairing the heartbeat with other browser signals
The heartbeat is one of several signals, and each answers a different question. The Long Tasks API, published by the W3C, measures responsiveness and associates long tasks with symptoms users perceive as a locked-up page, including janky animation or scrolling. It is complementary evidence, not a replacement for an independent heartbeat, because it is recorded from the page’s own task activity.
A basic Long Tasks observer looks like this. Check current support on MDN before relying on it in production:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →const longTaskObserver = new PerformanceObserver((list) => {n for (const entry of list.getEntries()) {n report('long-task', { durationMs: entry.duration, startTime: entry.startTime });n }n});nlongTaskObserver.observe({ entryTypes: ['longtask'] });
| Signal | Depends on the main thread running? | What it indicates | Behavior in hidden tabs | Can it prove a crash? |
|---|---|---|---|---|
| Worker heartbeat | Yes. The page must process the ping to reply. | A message was not handled within the configured threshold. | Timers may be throttled; compare against visibility state. | No |
| Long Tasks observations | Yes. Entries are produced when a long task finishes. | A task ran long enough to be recorded as a long task. | Not stated in the sources reviewed for this article. | No |
| Input responsiveness measurements | Yes. Input must be handled by the page. | User input was delayed. | Not stated in the sources reviewed for this article. | No |
| Page visibility state | No. It reports document state. | Whether the document is visible or hidden, and when that changed. | Is the context itself. | No |
No single row proves a freeze. Together, a heartbeat stall that coincides with a long task in a visible page is a much stronger signal than either alone. The sources reviewed here do not establish that these signals cover all perceived jank, so keep them as complementary rather than exhaustive.
Troubleshooting a suspected stall
When your watchdog reports a stall, work through the event before escalating it:
- Check visibility first. If
visibilityStatewas'hidden'for the whole interval, treat the event as background behavior until other evidence says otherwise. - Check for a matching long task. If a long-task entry overlaps the stall window, the page likely had a long synchronous task; look at what ran in that window.
- Check for a recovery event. A
recoveredevent with a similar elapsed time suggests a finite stall. If no recovery arrived, the page may still be stuck, or the worker may have stopped reporting; check whether the page is still rendering and whether the worker is alive. - Check whether the heartbeat handler was delayed. If the pong was late, verify that the page’s
onmessagehandler is small and does not wait on other work. - Check the threshold. If stalls are frequent but short, the threshold may be too tight for your application’s normal load on the target devices.
Limits of this pattern
The pattern tells you that something blocked the page’s message handling for longer than you allowed. It does not tell you why, and it does not replace error reporting or profiling. Use the heartbeat to decide when to capture more detail, such as the Long Tasks entries described above and a profile from the browser’s developer tools on a reproduction, rather than treating the watchdog itself as the diagnosis. The timing values in this article are examples, and no benchmark in the sources supports a specific default.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

