Docs

README

Module 19: Advanced DOM & Browser APIs

Master advanced DOM manipulation techniques and modern browser APIs for building rich, performant web applications.

╔═══════════════════════════════════════════════════════════════════════════════╗
β•‘                                                                               β•‘
β•‘     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β•‘
β•‘     β”‚              ADVANCED DOM & BROWSER APIS                        β”‚       β•‘
β•‘     β”‚                                                                 β”‚       β•‘
β•‘     β”‚    "Beyond the Basics - Professional Web Development"          β”‚       β•‘
β•‘     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β•‘
β•‘                                                                               β•‘
β•‘         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β•‘
β•‘         β”‚   OBSERVE    β”‚    β”‚   TRAVERSE   β”‚    β”‚   MEASURE    β”‚              β•‘
β•‘         β”‚   ────────   β”‚    β”‚   ────────   β”‚    β”‚   ────────   β”‚              β•‘
β•‘         β”‚  Mutation    β”‚    β”‚  TreeWalker  β”‚    β”‚  Performance β”‚              β•‘
β•‘         β”‚  Intersectionβ”‚    β”‚  NodeIteratorβ”‚    β”‚  Timing      β”‚              β•‘
β•‘         β”‚  Resize      β”‚    β”‚  Range/Selectβ”‚    β”‚  Metrics     β”‚              β•‘
β•‘         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β•‘
β•‘                                                                               β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•

πŸ“‹ Module Overview

This module takes you beyond basic DOM manipulation into the realm of professional-grade browser APIs. You'll learn to efficiently observe changes, traverse complex document structures, and measure performance with precision.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    WHY ADVANCED DOM APIs?                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  Traditional Approach:              Modern Observer Pattern:                β”‚
β”‚  ─────────────────────              ────────────────────────                β”‚
β”‚                                                                             β”‚
β”‚  setInterval(() => {                const observer = new                    β”‚
β”‚    checkForChanges();     VS        IntersectionObserver(callback);        β”‚
β”‚  }, 100);                           observer.observe(element);              β”‚
β”‚                                                                             β”‚
β”‚  ❌ Wasteful polling                βœ… Event-driven efficiency              β”‚
β”‚  ❌ Missed changes                  βœ… Guaranteed detection                 β”‚
β”‚  ❌ Battery drain                   βœ… Browser-optimized                    β”‚
β”‚  ❌ Performance hit                 βœ… Async, non-blocking                  β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“š Sections

19.1 Advanced DOM Traversal

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      DOM TRAVERSAL EVOLUTION                                β”‚
β”‚                                                                             β”‚
β”‚  Basic:                  Intermediate:             Advanced:                β”‚
β”‚  ───────                 ─────────────             ─────────                β”‚
β”‚  querySelector()    β†’    querySelectorAll()   β†’   TreeWalker                β”‚
β”‚  getElementById()   β†’    getElementsBy*       β†’   NodeIterator              β”‚
β”‚  parentNode         β†’    children             β†’   Range API                 β”‚
β”‚  firstChild         β†’    closest()            β†’   Selection API             β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • β€’TreeWalker - Flexible DOM tree navigation with custom filters
  • β€’NodeIterator - Sequential node traversal with filtering
  • β€’Range and Selection APIs - Programmatic text selection and manipulation
  • β€’Shadow DOM basics - Understanding encapsulated DOM structures

19.2 Mutation Observer

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        MUTATION OBSERVER                                    β”‚
β”‚                                                                             β”‚
β”‚     DOM Change Event                                                        β”‚
β”‚           β”‚                                                                 β”‚
β”‚           β–Ό                                                                 β”‚
β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                         β”‚
β”‚    β”‚   Browser    │──────► Batches Changes                                  β”‚
β”‚    β”‚   Engine     β”‚                 β”‚                                       β”‚
β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β–Ό                                       β”‚
β”‚                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                β”‚
β”‚                             β”‚  Mutation    β”‚                                β”‚
β”‚                             β”‚  Records     β”‚                                β”‚
β”‚                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                β”‚
β”‚                                     β”‚                                       β”‚
β”‚                                     β–Ό                                       β”‚
β”‚                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                β”‚
β”‚                             β”‚  Callback    │──────► Your Code               β”‚
β”‚                             β”‚  (async)     β”‚                                β”‚
β”‚                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                β”‚
β”‚                                                                             β”‚
β”‚  Observes: childList | attributes | characterData | subtree                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • β€’Observing DOM changes - React to any DOM modification
  • β€’Configuration options - Fine-tune what to observe
  • β€’Performance considerations - Avoiding callback storms
  • β€’Practical use cases - WYSIWYG editors, third-party script monitoring

19.3 Intersection Observer

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     INTERSECTION OBSERVER                                   β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚
β”‚  β”‚                        VIEWPORT                                     β”‚    β”‚
β”‚  β”‚                                                                     β”‚    β”‚
β”‚  β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                      β”‚    β”‚
β”‚  β”‚    β”‚ Element β”‚ ◄─── isIntersecting: true                           β”‚    β”‚
β”‚  β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      intersectionRatio: 0.75                        β”‚    β”‚
β”‚  β”‚                                                                     β”‚    β”‚
β”‚  β”‚- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - β”‚    β”‚
β”‚  β”‚    threshold: [0, 0.25, 0.5, 0.75, 1]                              β”‚    β”‚
β”‚  β”‚    rootMargin: "100px 0px"                                         β”‚    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚
β”‚  β”‚    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                                           β”‚
β”‚  β”‚    β”‚ Element β”‚ ◄─── isIntersecting: false (below viewport)              β”‚
β”‚  β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                                           β”‚
β”‚                                                                             β”‚
β”‚  Use Cases: Lazy Loading β€’ Infinite Scroll β€’ Analytics β€’ Animations        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • β€’Lazy loading images - Load content only when needed
  • β€’Infinite scroll - Dynamically load more content
  • β€’Analytics tracking - Track element visibility
  • β€’Animation triggers - Start animations on scroll

19.4 Resize Observer

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        RESIZE OBSERVER                                      β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚  β”‚                                    β”‚     β”‚                      β”‚        β”‚
β”‚  β”‚     Container Resizes              β”‚ ──► β”‚   Element Resizes    β”‚        β”‚
β”‚  β”‚                                    β”‚     β”‚                      β”‚        β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚                                                      β”‚                      β”‚
β”‚                                                      β–Ό                      β”‚
β”‚                                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚                                             β”‚   ResizeObserver     β”‚        β”‚
β”‚                                             β”‚   Callback Fires     β”‚        β”‚
β”‚                                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚                                                      β”‚                      β”‚
β”‚                                                      β–Ό                      β”‚
β”‚                                             β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚
β”‚                                             β”‚ contentRect:         β”‚        β”‚
β”‚                                             β”‚   width, height      β”‚        β”‚
β”‚                                             β”‚   top, left          β”‚        β”‚
β”‚                                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚
β”‚                                                                             β”‚
β”‚  Use Cases: Responsive Charts β€’ Container Queries β€’ Flexible Layouts        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • β€’Element resize detection - Know when any element changes size
  • β€’Responsive components - Build truly responsive widgets
  • β€’Performance optimization - Efficient resize handling

19.5 Performance Observer & APIs

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      PERFORMANCE MEASUREMENT                                β”‚
β”‚                                                                             β”‚
β”‚  Timeline:                                                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ navigationStart                                            loadEventβ”‚   β”‚
β”‚  β”‚      β”‚                                                          β”‚    β”‚   β”‚
β”‚  β”‚      β–Ό                                                          β–Ό    β”‚   β”‚
β”‚  β”‚      ●───────●───────●───────●───────●───────●───────●─────────●     β”‚   β”‚
β”‚  β”‚      β”‚       β”‚       β”‚       β”‚       β”‚       β”‚       β”‚         β”‚     β”‚   β”‚
β”‚  β”‚   redirect  fetch  connect  request  response  DOM    load   completeβ”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                             β”‚
β”‚  APIs:                                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                 β”‚
β”‚  β”‚ performance    β”‚  β”‚ Performance    β”‚  β”‚ Resource       β”‚                 β”‚
β”‚  β”‚ .now()         β”‚  β”‚ .mark()        β”‚  β”‚ Timing         β”‚                 β”‚
β”‚  β”‚ .measure()     β”‚  β”‚ .getEntries()  β”‚  β”‚ Navigation     β”‚                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                 β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • β€’Performance.now() - High-resolution timestamps
  • β€’Performance marks and measures - Custom timing metrics
  • β€’Navigation timing - Page load performance
  • β€’Resource timing - Individual resource load times

🎯 Learning Objectives

By the end of this module, you will:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          SKILL PROGRESSION                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  Level 1: Understanding                                                     β”‚
β”‚  β”œβ”€β”€ Explain the Observer pattern and its benefits                          β”‚
β”‚  β”œβ”€β”€ Understand when to use each Observer API                               β”‚
β”‚  └── Know the performance implications of DOM operations                    β”‚
β”‚                                                                             β”‚
β”‚  Level 2: Implementation                                                    β”‚
β”‚  β”œβ”€β”€ Implement lazy loading with IntersectionObserver                       β”‚
β”‚  β”œβ”€β”€ Track DOM changes with MutationObserver                                β”‚
β”‚  β”œβ”€β”€ Build responsive components with ResizeObserver                        β”‚
β”‚  └── Create custom performance metrics                                      β”‚
β”‚                                                                             β”‚
β”‚  Level 3: Optimization                                                      β”‚
β”‚  β”œβ”€β”€ Optimize observer callbacks for performance                            β”‚
β”‚  β”œβ”€β”€ Properly disconnect observers to prevent leaks                         β”‚
β”‚  └── Combine multiple observers efficiently                                 β”‚
β”‚                                                                             β”‚
β”‚  Level 4: Mastery                                                           β”‚
β”‚  β”œβ”€β”€ Build production-grade lazy loading systems                            β”‚
β”‚  β”œβ”€β”€ Create real-time performance monitoring dashboards                     β”‚
β”‚  └── Implement complex infinite scroll with virtual scrolling               β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“‹ Prerequisites

  • β€’Module 17: DOM Manipulation - Basic DOM concepts
  • β€’Module 15 & 16: Async JavaScript - Understanding callbacks and async patterns
  • β€’Understanding of browser event loop - How the browser schedules work

πŸ”‘ Key Concepts

The Observer Pattern in Browsers

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BROWSER OBSERVER PATTERN                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”‚
β”‚  β”‚MutationObserver β”‚   β”‚IntersectionObs. β”‚   β”‚ ResizeObserver  β”‚           β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€           β”‚
β”‚  β”‚ WHAT: DOM tree  β”‚   β”‚ WHAT: Viewport  β”‚   β”‚ WHAT: Element   β”‚           β”‚
β”‚  β”‚       changes   β”‚   β”‚       crossing  β”‚   β”‚       size      β”‚           β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€           β”‚
β”‚  β”‚ WHEN: childList β”‚   β”‚ WHEN: scroll,   β”‚   β”‚ WHEN: resize,   β”‚           β”‚
β”‚  β”‚  attr, charData β”‚   β”‚  resize, layout β”‚   β”‚  layout change  β”‚           β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€           β”‚
β”‚  β”‚ WHY: React to   β”‚   β”‚ WHY: Lazy load, β”‚   β”‚ WHY: Responsive β”‚           β”‚
β”‚  β”‚   DOM mutations β”‚   β”‚   infinite scrl β”‚   β”‚   components    β”‚           β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β”‚
β”‚                                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                 β”‚
β”‚  β”‚PerformanceObs.  β”‚   β”‚ ReportingObs.   β”‚                                 β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                 β”‚
β”‚  β”‚ WHAT: Perf      β”‚   β”‚ WHAT: Browser   β”‚                                 β”‚
β”‚  β”‚       entries   β”‚   β”‚       reports   β”‚                                 β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                 β”‚
β”‚  β”‚ WHEN: Timing    β”‚   β”‚ WHEN: CSP, dep. β”‚                                 β”‚
β”‚  β”‚  marks, navs    β”‚   β”‚  crashes, etc   β”‚                                 β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€   β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€                                 β”‚
β”‚  β”‚ WHY: Measure &  β”‚   β”‚ WHY: Error &    β”‚                                 β”‚
β”‚  β”‚   optimize      β”‚   β”‚   security mon. β”‚                                 β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                 β”‚
β”‚                                                                             β”‚
β”‚  Common Benefits:                                                           β”‚
β”‚  βœ… No polling required     βœ… Browser-optimized callbacks                 β”‚
β”‚  βœ… Async execution         βœ… Batched updates                              β”‚
β”‚  βœ… Memory efficient        βœ… Proper cleanup with disconnect()             β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Observer API Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Observer         β”‚ What It Observes      β”‚ Key Configuration                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Mutation         β”‚ DOM tree changes      β”‚ childList, attributes, subtree     β”‚
β”‚ Intersection     β”‚ Element visibility    β”‚ threshold, rootMargin, root        β”‚
β”‚ Resize           β”‚ Element dimensions    β”‚ box (content-box, border-box)      β”‚
β”‚ Performance      β”‚ Performance entries   β”‚ entryTypes, buffered               β”‚
β”‚ Reporting        β”‚ Browser reports       β”‚ types (deprecation, csp, crash)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ’‘ Common Patterns

Pattern 1: Basic Observer Setup

// All observers follow this pattern:
const observer = new SomeObserver(callback, options);
observer.observe(target);
// ... later
observer.disconnect();

Pattern 2: Lazy Loading Images

const lazyLoad = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      lazyLoad.unobserve(img);
    }
  });
});

document
  .querySelectorAll('img[data-src]')
  .forEach((img) => lazyLoad.observe(img));

Pattern 3: Infinite Scroll

const sentinel = document.querySelector('#load-more-sentinel');

const infiniteScroll = new IntersectionObserver(
  (entries) => {
    if (entries[0].isIntersecting) {
      loadMoreContent();
    }
  },
  { rootMargin: '100px' }
);

infiniteScroll.observe(sentinel);

🎯 Practical Applications

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     REAL-WORLD USE CASES                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  MutationObserver:                                                          β”‚
β”‚  β”œβ”€β”€ WYSIWYG editor undo/redo                                               β”‚
β”‚  β”œβ”€β”€ Third-party script injection detection                                 β”‚
β”‚  β”œβ”€β”€ Dynamic content accessibility                                          β”‚
β”‚  └── Form validation on dynamic inputs                                      β”‚
β”‚                                                                             β”‚
β”‚  IntersectionObserver:                                                      β”‚
β”‚  β”œβ”€β”€ Image/video lazy loading                                               β”‚
β”‚  β”œβ”€β”€ Infinite scroll pagination                                             β”‚
β”‚  β”œβ”€β”€ Scroll-triggered animations                                            β”‚
β”‚  β”œβ”€β”€ Ad viewability tracking                                                β”‚
β”‚  └── Read progress indicators                                               β”‚
β”‚                                                                             β”‚
β”‚  ResizeObserver:                                                            β”‚
β”‚  β”œβ”€β”€ Responsive data visualization                                          β”‚
β”‚  β”œβ”€β”€ Container query polyfills                                              β”‚
β”‚  β”œβ”€β”€ Textarea auto-resize                                                   β”‚
β”‚  └── Responsive image switching                                             β”‚
β”‚                                                                             β”‚
β”‚  Performance APIs:                                                          β”‚
β”‚  β”œβ”€β”€ Real user monitoring (RUM)                                             β”‚
β”‚  β”œβ”€β”€ Custom performance dashboards                                          β”‚
β”‚  β”œβ”€β”€ A/B test performance comparison                                        β”‚
β”‚  └── Web vitals tracking                                                    β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚠️ Common Pitfalls & Best Practices

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        PITFALLS TO AVOID                                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  ❌ Memory Leaks                    βœ… Always Disconnect                    β”‚
β”‚  ─────────────────                  ────────────────────                    β”‚
β”‚  // Forgot to disconnect            // Clean up properly                   β”‚
β”‚  observer.observe(el);              observer.observe(el);                   β”‚
β”‚  // Element removed, leak!          // When done:                           β”‚
β”‚                                      observer.disconnect();                 β”‚
β”‚                                                                             β”‚
β”‚  ❌ Callback Storms                 βœ… Debounce/Throttle                    β”‚
β”‚  ─────────────────                  ───────────────────                     β”‚
β”‚  // Every tiny change               // Batch processing                     β”‚
β”‚  callback: (mutations) => {         callback: (mutations) => {              β”‚
β”‚    expensiveOperation();              requestAnimationFrame(() =>           β”‚
β”‚  }                                      batchedOperation(mutations)         β”‚
β”‚                                       );                                    β”‚
β”‚                                     }                                       β”‚
β”‚                                                                             β”‚
β”‚  ❌ Over-Observing                  βœ… Precise Configuration                β”‚
β”‚  ─────────────────                  ────────────────────────                β”‚
β”‚  { subtree: true,                   { subtree: false,  // Only direct       β”‚
β”‚    attributes: true,                  attributeFilter: ['class'],           β”‚
β”‚    characterData: true }              childList: true }                     β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“š Section Files

SectionTopicKey Files
19.1Advanced DOM Traversal01-tree-walker.js, 02-node-iterator.js, 03-range-api.js
19.2Mutation Observer01-basic-mutation.js, 02-attribute-observer.js
19.3Intersection Observer01-lazy-loading.js, 02-infinite-scroll.js
19.4Resize Observer01-responsive-component.js, 02-chart-resize.js
19.5Performance APIs01-performance-marks.js, 02-timing-api.js

πŸ”— Related Modules


πŸ“– Quick Reference Card

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    OBSERVER QUICK REFERENCE                                 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  // MutationObserver                                                        β”‚
β”‚  const mo = new MutationObserver(callback);                                 β”‚
β”‚  mo.observe(node, { childList: true, subtree: true });                      β”‚
β”‚  mo.disconnect();                                                           β”‚
β”‚                                                                             β”‚
β”‚  // IntersectionObserver                                                    β”‚
β”‚  const io = new IntersectionObserver(callback, { threshold: 0.5 });         β”‚
β”‚  io.observe(element);                                                       β”‚
β”‚  io.unobserve(element);                                                     β”‚
β”‚  io.disconnect();                                                           β”‚
β”‚                                                                             β”‚
β”‚  // ResizeObserver                                                          β”‚
β”‚  const ro = new ResizeObserver(callback);                                   β”‚
β”‚  ro.observe(element);                                                       β”‚
β”‚  ro.unobserve(element);                                                     β”‚
β”‚  ro.disconnect();                                                           β”‚
β”‚                                                                             β”‚
β”‚  // PerformanceObserver                                                     β”‚
β”‚  const po = new PerformanceObserver(callback);                              β”‚
β”‚  po.observe({ entryTypes: ['measure', 'mark'] });                           β”‚
β”‚  po.disconnect();                                                           β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
README - JavaScript Tutorial | DeepML