<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/medium-w2o7cicnw" -->

---
title: Medium | daily.dev
description: A deep dive into how JavaScript's single-threaded architecture can be exploited to crash or severely degrade web applications. Covers four escalating...
canonical: https://daily.dev/posts/medium-w2o7cicnw
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Medium | daily.dev
og:description: A deep dive into how JavaScript's single-threaded architecture can be exploited to crash or severely degrade web applications. Covers four escalating...
og:url: https://daily.dev/posts/medium-w2o7cicnw
og:image: https://api.daily.dev/og/posts/W2O7CiCnW.png
og:image:alt: Medium
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Medium

**[Medium](https://daily.dev/sources/medium_js)** · 10 min read · 0 upvotes · 0 comments

## Summary

A deep dive into how JavaScript's single-threaded architecture can be exploited to crash or severely degrade web applications. Covers four escalating techniques: synchronous call stack blocking (infinite loops, heavy recursion, programmatic DOM triggers), microtask starvation via recursive Promise chains, macrotask queue flooding with thousands of setTimeout calls, and layout thrashing by interleaving DOM reads and writes. Each technique is explained with code examples and the underlying browser mechanics. Also includes diagnostic tips using Chrome DevTools and the PerformanceObserver API, and concludes with best practices like batching DOM reads before writes and avoiding recursive promise patterns.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://medium.com/@AronnoAhsan/how-to-crash-a-website-using-javascript-weaponizing-the-event-loop-7fbaabf5a329>

## Questions this post answers

### why does calling button.click() programmatically inside its own click handler crash the browser tab

Programmatic DOM triggers like .click(), .focus(), and dispatchEvent() run synchronously rather than going through the task queue like real user clicks. When a click handler calls button.click() on itself, the browser pauses the current script and executes the handler immediately, recursively growing the call stack until it hits a stack overflow or the browser freezes. Wrapping the call in setTimeout(() => button.click(), 0) pushes it onto the macrotask queue instead, avoiding the crash.

_Debugging synchronous DOM event traps gets easier when you track patterns like this via daily.dev._

### how can a recursive Promise.then callback freeze a web page without throwing any errors

A function that recursively calls Promise.resolve().then(itself) causes microtask starvation: the event loop must fully drain the microtask queue before it can render or process macrotasks, and each recursive call adds a new microtask before the queue empties, so it never reaches zero. The loop gets trapped processing microtasks forever, so the page freezes silently with no syntax error and no infinite loop in sight.

_Spotting silent microtask starvation bugs is easier when you follow event loop deep dives on daily.dev._

### why does flooding setTimeout with thousands of calls cause UI jank instead of crashing the tab like an infinite loop does

The event loop processes only one macrotask per tick and yields back to check for layout or repaint work before moving to the next, and browsers clamp nested setTimeout calls to a minimum 4ms delay, so a single recursive setTimeout chain stays responsive. Flooding the queue with tens of thousands of setTimeout calls at once stretches the time between render ticks, dropping frame rates from 60fps to single digits without fully blocking the page.

_Understanding macrotask scheduling limits helps when diagnosing jank, a topic you can follow on daily.dev._

## Similar posts on daily.dev

- [Mastering the JavaScript Event Loop](https://daily.dev/posts/mastering-the-javascript-event-loop-xrcdqa1q5) · freeCodeCamp · 26 upvotes · 0 comments
- [How the JavaScript Runtime Schedules Callbacks: A Look at the Event Loop](https://daily.dev/posts/how-the-javascript-runtime-schedules-callbacks-a-look-at-the-event-loop-qkr1ufg7o) · Medium · 4 upvotes · 0 comments
- [The Browser's Main Thread Is Expensive](https://daily.dev/posts/the-browser-s-main-thread-is-expensive-2bvhrzwda) · Lobsters · 1 upvotes · 1 comments
- [20 Mistakes That Quietly Destroy JavaScript/TypeScript Codebases \(Part 2\)](https://daily.dev/posts/20-mistakes-that-quietly-destroy-javascript-typescript-codebases-part-2--lgbflmz2i) · The T-Shaped Dev · 59 upvotes · 1 comments
- [Stop Calling Node.js “Single-Threaded”: A Look Under the Hood](https://daily.dev/posts/stop-calling-node-js-single-threaded-a-look-under-the-hood-ofsmhbjmm) · Medium · 6 upvotes · 0 comments

---

Tags: [#javascript](https://daily.dev/tags/javascript)

[View this post on daily.dev](https://daily.dev/posts/medium-w2o7cicnw)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Medium","url":"https://daily.dev/posts/medium-w2o7cicnw","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/medium-w2o7cicnw"},"datePublished":"2026-07-21T20:07:08.287Z","dateModified":"2026-09-14T08:57:17.762Z","description":"A deep dive into how JavaScript's single-threaded architecture can be exploited to crash or severely degrade web applications. Covers four escalating...","image":"https://media.daily.dev/image/upload/s--qPvKM23u--/f_auto/v1722860399/public/Placeholder%2009","thumbnailUrl":"https://media.daily.dev/image/upload/s--qPvKM23u--/f_auto/v1722860399/public/Placeholder%2009","isAccessibleForFree":true,"articleSection":"Medium","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Medium","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/medium","url":"https://daily.dev/sources/medium_js"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/medium-w2o7cicnw","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"javascript","timeRequired":"PT10M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Medium","item":"https://daily.dev/sources/medium_js"},{"@type":"ListItem","position":3,"name":"Medium"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/medium-w2o7cicnw#faq","mainEntity":[{"@type":"Question","name":"why does calling button.click() programmatically inside its own click handler crash the browser tab","acceptedAnswer":{"@type":"Answer","text":"Programmatic DOM triggers like .click(), .focus(), and dispatchEvent() run synchronously rather than going through the task queue like real user clicks. When a click handler calls button.click() on itself, the browser pauses the current script and executes the handler immediately, recursively growing the call stack until it hits a stack overflow or the browser freezes. Wrapping the call in setTimeout(() => button.click(), 0) pushes it onto the macrotask queue instead, avoiding the crash. Debugging synchronous DOM event traps gets easier when you track patterns like this via daily.dev."}},{"@type":"Question","name":"how can a recursive Promise.then callback freeze a web page without throwing any errors","acceptedAnswer":{"@type":"Answer","text":"A function that recursively calls Promise.resolve().then(itself) causes microtask starvation: the event loop must fully drain the microtask queue before it can render or process macrotasks, and each recursive call adds a new microtask before the queue empties, so it never reaches zero. The loop gets trapped processing microtasks forever, so the page freezes silently with no syntax error and no infinite loop in sight. Spotting silent microtask starvation bugs is easier when you follow event loop deep dives on daily.dev."}},{"@type":"Question","name":"why does flooding setTimeout with thousands of calls cause UI jank instead of crashing the tab like an infinite loop does","acceptedAnswer":{"@type":"Answer","text":"The event loop processes only one macrotask per tick and yields back to check for layout or repaint work before moving to the next, and browsers clamp nested setTimeout calls to a minimum 4ms delay, so a single recursive setTimeout chain stays responsive. Flooding the queue with tens of thousands of setTimeout calls at once stretches the time between render ticks, dropping frame rates from 60fps to single digits without fully blocking the page. Understanding macrotask scheduling limits helps when diagnosing jank, a topic you can follow on daily.dev."}}]}
```

