Skip to content

Latest commit

ย 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Loopscope

An interactive JavaScript Event Loop visualizer โ€” paste real code, watch it actually run through the Call Stack, Web APIs, Microtask Queue, and Callback Queue.

JavaScript ES2022 No build step Dependencies: Acorn MIT License

๐Ÿ”— Live Demo โ†’ (replace with your GitHub Pages URL after deploying, e.g. https://yourname.github.io/loopscope/)


๐Ÿ“– Table of Contents


๐Ÿง  What is this?

Most "event loop visualizers" animate a handful of hardcoded example snippets. Loopscope is different โ€” it's a real, hand-built JavaScript interpreter (parsing with Acorn) wired to its own virtual scheduler, so you can paste any JavaScript you want and watch the actual execution order unfold:

  • Function calls landing on the Call Stack
  • Async work (setTimeout, fetch) handed off to Web APIs
  • Promise reactions and queueMicrotask piling up in the Microtask Queue
  • Timer callbacks waiting their turn in the Callback Queue

The entire run is computed instantly against a virtual clock, then replayed step-by-step so you can scrub through it like a debugger โ€” play, pause, step forward, step backward, adjust speed โ€” with the current line highlighted in the editor as you go.

โœจ Why it's different

Typical event loop visualizer Loopscope
A few fixed, hardcoded demos Paste any JavaScript
Animation is scripted by hand Animation is a real execution trace
No feedback on your own code Full interpreter: closures, classes, destructuring, async/await, promises, try/catch, loops...
Just shows queues moving Every step has a plain-English explanation of why it happened
No teaching material Ships with a full written guide (beginner โ†’ advanced) baked into the page

๐Ÿ–ผ Preview

(Add a screenshot or GIF here once deployed โ€” this section is a great place for a docs/preview.gif showing the Run โ†’ Trace โ†’ Playback flow.)

docs/
  preview.png   โ† recommended: full-app screenshot
  demo.gif      โ† recommended: 5โ€“10s clip of stepping through a trace
![Loopscope preview](docs/preview.png)

๐Ÿš€ Features

  • ๐Ÿงฉ Custom interpreter โ€” parses your code with Acorn and tree-walks it, delegating to real JS natives (Math, JSON, array/string/object methods) so the data behaves exactly like real JavaScript.
  • โฑ Accurate async simulation โ€” setTimeout / setInterval / clearTimeout / clearInterval, real Promise semantics (then / catch / finally / all / race / allSettled / any), async/await suspension & resumption, queueMicrotask, and a mocked fetch with simulated network delay.
  • ๐Ÿ— Modern syntax support โ€” closures, all control flow (if/for/while/do-while/for-of/for-in/switch/try-catch-finally), destructuring (objects & arrays, defaults, rest), spread/rest, template literals, classes (constructor, methods, getters/setters, static, extends/super), labeled break/continue.
  • ๐ŸŽฌ Full playback controls โ€” play/pause, step forward/back, adjustable speed, live line highlighting in the editor.
  • ๐Ÿ—ฃ Beginner-friendly explanations โ€” every step in the trace comes with a plain-English "why," not just a mechanical log line.
  • ๐ŸŽจ Distinct, non-generic dark UI โ€” four color-coded panels (Call Stack, Web APIs, Microtask Queue, Callback Queue) that visually mirror the real event loop diagram.
  • โœ๏ธ Live "custom code" detection โ€” the sample dropdown automatically switches to "โœŽ Custom code" the moment you edit or paste your own script.
  • ๐Ÿ“š Full built-in guide โ€” a complete, SEO-friendly article covering the event loop from first principles to Node.js internals, with a table of contents, glossary, and FAQ.
  • ๐Ÿ›ก Safety guards โ€” infinite-loop protection, step-count caps, and graceful syntax/runtime error reporting.
  • ๐ŸŒ Zero build step โ€” plain HTML/CSS/JS. Open the file or host it as a static site; no npm install, no bundler.

โš™๏ธ How it works internally

Loopscope doesn't just animate pre-scripted timelines โ€” it actually runs your code once, instantly, against a virtual event loop, recording every meaningful moment (a function call, a scheduled timer, a microtask draining, a console log) as a discrete step with a full snapshot of all four panels. Playback simply replays that recorded array of steps.

Your code
   โ”‚
   โ–ผ
Acorn parser  โ”€โ”€โ–บ  AST
   โ”‚
   โ–ผ
Tree-walking interpreter (generator-based, so `await` can suspend)
   โ”‚
   โ”œโ”€โ”€ Call Stack        โ†’ real push/pop tracking per function call
   โ”œโ”€โ”€ Web APIs           โ†’ virtual timers & mocked fetch, keyed by virtual clock time
   โ”œโ”€โ”€ Microtask Queue     โ†’ custom Promise implementation (VPromise) + queueMicrotask
   โ””โ”€โ”€ Callback Queue      โ†’ macrotasks released once due, one per event-loop tick
   โ”‚
   โ–ผ
Full step trace (array of snapshots)
   โ”‚
   โ–ผ
UI playback (scrub / play / step)

Key design choices:

  • Real values, custom control flow. Numbers, strings, arrays, and objects are genuine JS values โ€” only scheduling primitives (setTimeout, Promise, queueMicrotask, fetch, console) are intercepted, so the full native standard library "just works."
  • Generators for await. The interpreter's statement/expression evaluators are JS generator functions, so an await can yield and suspend exactly at that point โ€” mirroring real async function semantics (the caller gets control back immediately with a pending promise).
  • Deterministic virtual clock. Timer delays advance a virtual clock rather than real wall-clock time, so the whole trace computes synchronously and instantly, no matter the delays used in your code.

๐Ÿ“ Project structure

.
โ”œโ”€โ”€ index.html      # Markup: editor, four visualizer panels, transport controls, full guide article
โ”œโ”€โ”€ styles.css       # Dark theme, panel layout, responsive rules, docs/article styling
โ”œโ”€โ”€ script.js         # Interpreter core (Acorn-based), virtual scheduler, and UI wiring
โ””โ”€โ”€ README.md          # You are here

Note: if you split the original single-file build into these three files, double-check that:

  • index.html loads Acorn before script.js (<script src="https://cdnjs.cloudflare.com/ajax/libs/acorn/8.11.3/acorn.min.js"></script> first, then <script src="script.js"></script> at the end of <body>).
  • index.html has <link rel="stylesheet" href="styles.css"> in <head>.
  • All ids referenced in script.js (codeInput, sampleSelect, stackBody, webapiBody, microBody, macroBody, consoleBody, stepDesc, stepWhy, stepCount, playBtn, stepBackBtn, stepFwdBtn, speedRange, runBtn, clearBtn, customBadge, gutterHighlight, lineNumbers) still exist in index.html with matching names.

๐Ÿ“˜ Usage guide

  1. Pick a sample from the dropdown, or paste your own JavaScript into the editor.
  2. Click โ–ถ Run & Trace โ€” your code executes instantly against the virtual scheduler.
  3. Use the transport controls at the bottom:
    • โฎ / โญ โ€” step backward / forward one action at a time
    • โ–ถ / โธ โ€” auto-play through the whole trace
    • speed slider โ€” control playback speed
  4. Watch the four panels:
    • ๐Ÿ”ต Call Stack โ€” what's executing right now
    • ๐ŸŸ  Web APIs โ€” async work happening in the background
    • ๐ŸŸฃ Microtask Queue โ€” promise reactions & queueMicrotask, always drained first
    • ๐ŸŸข Callback Queue โ€” setTimeout/setInterval callbacks, one run per loop tick
  5. Read the description + "why" explanation under the controls for what just happened and why.
  6. Scroll down for the full written guide if you want the concepts explained from scratch.

โœ… Supported vs. unsupported JavaScript

Supported

  • Closures, all control flow, labeled break/continue
  • Destructuring (objects/arrays, defaults, rest) in declarations, params, and assignments
  • Spread/rest, template literals, optional chaining (?.), nullish coalescing (??)
  • Classes: constructors, methods, getters/setters, static members, extends/super()/super.method()
  • Promises (then/catch/finally/all/race/allSettled/any), async/await
  • setTimeout, setInterval, clearTimeout, clearInterval, queueMicrotask
  • Full native standard library โ€” Math, JSON, Array/String/Object/Map/Set methods, etc.

Not supported

  • Generators (function*)
  • True private class fields (#x is tolerated but not genuinely private)
  • Decorators
  • ES Modules (import/export)
  • DOM APIs
  • fetch is mocked โ€” it simulates a network delay and returns fake data; there is no real networking

setInterval auto-stops after 8 firings so traces stay finite.

๐Ÿ”„ The Event Loop โ€” quick primer

1. Run all synchronous code top-to-bottom.
2. Call Stack empty? โ†’ drain the ENTIRE Microtask Queue
   (including new microtasks scheduled while draining).
3. Take ONE task from the Callback Queue, run it.
4. Go back to step 2. Forever.
  • Microtasks always win. Every pending .then()/await continuation runs before the next setTimeout callback โ€” even a setTimeout(fn, 0) scheduled earlier.
  • Only one macrotask per tick. This is what gives the browser room to repaint between timer callbacks.
  • Blocking the stack blocks everything. A long synchronous loop freezes timers, promises, clicks, and rendering alike โ€” there's only one thread.

The full in-app guide covers this in much more depth: Call Stack mechanics, Web APIs vs. Node APIs, async/await desugaring, rendering timing, Node.js's phase-based event loop (libuv), and common real-world pitfalls (microtask starvation, setTimeout(0) myths, memory leaks from lingering timers).

๐Ÿงพ Reading the step explanations

Step Meaning
Call Stack push A function call just started and was placed on top of the stack.
Call Stack pop The function finished and was removed from the stack.
Web APIs โ€” added An async op (setTimeout, fetch) was handed off to run in the background.
Callback Queue โ€” added The Web API finished; its callback is now waiting its turn.
Callback Queue โ€” running Stack + microtasks empty โ€” the oldest queued callback now runs.
Microtask Queue โ€” added A promise settled or queueMicrotask was called.
Microtask Queue โ€” running The next microtask runs โ€” always before the next macrotask.

๐Ÿ›  Tech stack

  • Vanilla HTML / CSS / JavaScript โ€” no framework, no build step
  • Acorn (via CDN) โ€” JavaScript parser, used only to produce the AST the interpreter walks

๐Ÿ—บ Roadmap

  • Generator function (function*) support
  • Shareable trace links (encode code in URL)
  • Dark/light theme toggle
  • requestAnimationFrame lane in the visualizer
  • Export trace as GIF/video

๐Ÿค Contributing

Issues and PRs are welcome โ€” this is a static, dependency-light project, so contributing is just: fork, edit index.html / styles.css / script.js, test in a browser, and open a PR.

โ“ FAQ

Do microtasks or macrotasks run first? Microtasks always run first, completely, before the next macrotask โ€” even ones scheduled while others are draining.

Is setTimeout(fn, 0) really immediate? No โ€” it still waits for the current call stack and the full microtask queue to clear first.

Why does fetch show fake data? There's no real networking in this sandboxed interpreter. fetch is mocked with a simulated delay so its position in the event loop stays accurate, even though the response is fabricated.

Can this run in production apps? No โ€” this is an educational tool. It's not a JS engine replacement and doesn't aim for 100% spec compliance (see Supported vs. unsupported).

๐Ÿ“„ License

MIT โ€” free to use, modify, and distribute. Add a LICENSE file with the standard MIT text if you haven't already.

Releases

Packages

Contributors

Languages