Refresher Reminder
🌐
JavaScript in the Browser
Everything specific to running JS inside web pages
🪟 Window
📄 Document
🌳 DOM APIs
📦 Script Loading
🎯 Events
📡 AJAX
📚 General JavaScript refresher content lives in Refresher and stays exactly the same.
The window Global
Each browser tab has a top-level global object: window. It exposes:
🪟 Window Object Properties
🌍 Environment
location
navigator
history
screen
⏱️ Timing
setTimeout
setInterval
requestAnimationFrame
💬 Dialogs / Console
alert
prompt
confirm
console
💡 Tip: You can omit window. for global functions: alert("Hi") equals window.alert("Hi")
Copy Try it console.log("Current URL:", window.location.href);
console.log("User Agent:", window.navigator.userAgent);
console.log("Screen size:", window.screen.width, "x", window.screen.height);
// Timing example
window.setTimeout(() => console.log("Timer fired after 500ms"), 500);
// Another way (window. is optional)
setTimeout(() => console.log("Same timer syntax"), 600);
The document Object
document represents the loaded HTML page. Key properties:
📄 Document Quick Reference
📍 Element Shortcuts
document.documentElement
→ <html> element
document.head
→ <head> element
document.body
→ <body> element
ℹ️ Info Properties
document.title
(read/write)
document.URL
document.referrer
🔄 Ready State
document.readyState
loading
interactive
complete
Copy Try it // Change the page title (watch the browser title bar!)
document.title = "My Custom Title!";
console.log("Title set to:", document.title);
// Create visible content
document.body.innerHTML = `
<h1>Hello from JavaScript!</h1>
<p>This content was created dynamically.</p>
<div class="demo-box">
<strong>Document Info:</strong>
<ul>
<li>Ready State: ${document.readyState}</li>
<li>Character Set: ${document.characterSet}</li>
<li>Content Type: ${document.contentType}</li>
</ul>
</div>
`;
console.log("Page content updated!");
console.log("Ready state:", document.readyState);
💡 Tip: Watch the browser preview panel — the title bar will update when you change document.title!
The DOM Tree
The DOM (Document Object Model ) is a tree of nodes .
🌳 DOM Tree Structure
📦 Element nodes
📝 Text nodes
💬 Comment nodes
📎 Attribute nodes
⬆️ Parent Access
node.parentNode
Every node may have a parent
⬇️ Children Access
children
(elements only)
childNodes
(all node types)
↔️ Siblings
nextElementSibling
previousElementSibling
DOM Inheritance Hierarchy
Accurate core DOM type relationships (simplified). Hollow triangle points to the parent.
▼ Node
📄 Document
📄 DocumentType
📄 DocumentFragment
▼ Element
▼ HTMLElement
📄 HTMLDivElement
📄 HTMLButtonElement
📄 HTMLInputElement
📄 HTMLSpanElement
⋯ and many more
▶ SVGElement
📄 SVGCircleElement
📄 SVGPathElement
⋯ more
▼ CharacterData
📄 Text
📄 Comment
📄 CDATASection
📄 ProcessingInstruction
📎 Attr
Not a Node (since DOM4)
Selecting Nodes & Elements
🎯 Selection Methods
document.getElementById(id)
Single element by ID
⚡ Fastest
document.querySelector(css)
First match (any CSS selector)
🎨 Flexible
document.querySelectorAll(css)
All matches → static NodeList
📋 Static
getElementsByClassName(name)
By class → live HTMLCollection
🔄 Live
getElementsByTagName(tag)
By tag → live HTMLCollection
🔄 Live
📋 Static NodeList
Snapshot at query time. DOM changes don't affect it.
🔄 Live HTMLCollection
Auto-updates when DOM changes. Can cause issues in loops!
🚀 Direct access:
document.body,
document.head,
document.documentElement
Copy Try it // First, create some demo HTML
document.body.innerHTML = `
<div id="demo-main" class="demo-box">
<h2>Main Container</h2>
<button class="demo-btn primary">Primary Button</button>
<button class="demo-btn">Secondary</button>
<p class="demo-text">Some text here</p>
</div>
`;
// Get element by ID
const main = document.querySelector("#demo-main");
console.log("Found element:", main.tagName);
// Get all buttons
const buttons = document.querySelectorAll(".demo-btn");
console.log("Number of buttons:", buttons.length);
// Loop through buttons
buttons.forEach((btn, i) => {
console.log("Button " + i + ":", btn.textContent);
btn.setAttribute("style", "border: 3px solid lime;");
});
// Get first primary button
const primary = document.querySelector(".demo-btn.primary");
if (primary) {
primary.setAttribute("style", "background: #4CAF50; color: white;");
console.log("Primary button highlighted!");
}
Content & Attribute Manipulation
📝 Text/Content APIs Comparison
textContent
✅ Safe
⚡ Fast
Raw text only. No layout cost. HTML is escaped as text.
innerText
⚠️ Reflow
Respects CSS visibility. Triggers layout/reflow reads.
innerHTML
⚠️ XSS Risk
Parses HTML. Never use with untrusted input!
🔒 Security: Sanitize external HTML (e.g. DOMPurify) or build nodes manually.
📎 Dataset API (data-* attributes)
HTML Attribute
data-user-id="123"
→
JavaScript Access
element.dataset.userId
WRITE
el.dataset.key = "val"
DELETE
delete el.dataset.key
⚠️ Use dataset NOT data: el.dataset.ok ✅ vs el.data.ok ❌
Copy Try it // Create demo elements
document.body.innerHTML = `
<div id="panel" class="demo-box">
<p>Original content</p>
</div>
<input type="text" id="email" placeholder="Enter email">
`;
const panel = document.querySelector("#panel");
// textContent - treats HTML as literal text
panel.textContent = "<span>This shows as TEXT</span>";
console.log("1. textContent set (HTML escaped)");
// After 1s, use innerHTML
setTimeout(() => {
panel.innerHTML = "<strong style='color:#4CAF50'>Bold HTML!</strong>";
console.log("2. innerHTML set (renders HTML)");
}, 1000);
// Work with input attributes
const input = document.querySelector("#email");
input.value = "user@example.com";
input.setAttribute("placeholder", "Email updated!");
console.log("Input value:", input.value);
// === Dataset API Examples ===
// CORRECT: use element.dataset (not element.data!)
panel.dataset.state = "active"; // creates data-state="active"
panel.dataset.userId = "12345"; // creates data-user-id="12345"
panel.dataset.ok = "works!"; // creates data-ok="works!"
panel.dataset.myCustomValue = "abc"; // creates data-my-custom-value="abc"
console.log("dataset.state:", panel.dataset.state);
console.log("dataset.userId:", panel.dataset.userId);
console.log("dataset.ok:", panel.dataset.ok);
// Read via getAttribute too
console.log("getAttribute:", panel.getAttribute("data-ok"));
// Delete a data attribute
delete panel.dataset.ok;
console.log("After delete, ok:", panel.dataset.ok); // undefined
Creating & Inserting Elements
🛠️ Creating & Inserting Methods
CREATE
document.createElement(tag)
APPEND (end)
parent.appendChild(node)
parent.append(...nodes)
PREPEND (start)
parent.prepend(node)
INSERT HTML
insertAdjacentHTML(pos, html)
📍 insertAdjacentHTML positions:
"beforebegin" → before element
<div>
"afterbegin" → first child
...content...
"beforeend" → last child
</div>
"afterend" → after element
🚀 DocumentFragment - Batch Insertions
Every DOM modification triggers a reflow/repaint (expensive!)
❌ Without Fragment
Adding 100 items = 100 reflows!
for(i) { parent.appendChild(item) }
✅ With Fragment
Adding 100 items = 1 reflow!
frag = createDocumentFragment() for(i) { frag.appendChild(item) } parent.appendChild(frag)
💾 Lives in memory only
👻 Fragment disappears after insert
📊 Perfect for lists & tables
🎮 Interactive Playground - Try It!
Choose Method:
prepend()
append()
beforebegin
afterbegin
beforeend
afterend
New element content:
➕ Insert Element
🔄 Reset
Generated Code:
container.prepend(newElement);
Live Preview:
⬆️ beforebegin zone (outside)
📦 CONTAINER (target element)
📦 Item 1 (original)
📦 Item 2 (original)
📦 Item 3 (original)
⬇️ afterend zone (outside)
🔵 Original
🟢 New
🟠 Outside
🔷 Inside
📝 Quick Examples
Copy Try it // 1. Create element
const div = document.createElement("div");
div.textContent = "Hello!";
div.className = "my-class";
// 2. Insert methods
const container = document.body;
container.prepend(div); // First child
container.append(div); // Last child
container.appendChild(div); // Same as append
// 3. insertAdjacentHTML positions
container.insertAdjacentHTML("beforebegin", "<p>Before</p>");
container.insertAdjacentHTML("afterbegin", "<p>First inside</p>");
container.insertAdjacentHTML("beforeend", "<p>Last inside</p>");
container.insertAdjacentHTML("afterend", "<p>After</p>");
// 4. DocumentFragment for batch inserts
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const item = document.createElement("div");
item.textContent = "Item " + i;
fragment.appendChild(item); // No reflow yet!
}
container.appendChild(fragment); // ONE reflow!
console.log("Elements created and inserted!");
Traversal & Relationships
🧭 DOM Navigation Properties
↑ parentNode
│
children ↓
← previous
firstElementChild
Child 1
⇄
⇄
next →
previousElementSibling
nextElementSibling
CHILDREN (elements only)
element.children
CHILD NODES (all types)
element.childNodes
SIBLINGS
nextElementSibling
previousElementSibling
Element Properties
Returns only element nodes (tags)
Node Properties
Includes text, comments, etc.
Copy Try it // Create article container
document.body.innerHTML = `
<div id="articles">
<article class="demo-box">Article 1</article>
<article class="demo-box">Article 2</article>
<article class="demo-box">Article 3</article>
</div>
`;
const container = document.querySelector("#articles");
// Children info
console.log("Element children:", container.children.length);
console.log("All child nodes:", container.childNodes.length);
// First and last element child
const first = container.firstElementChild;
const last = container.lastElementChild;
first.setAttribute("style", "background: #4CAF50; color: white; padding: 10px;");
console.log("First child:", first.textContent);
last.setAttribute("style", "background: #2196F3; color: white; padding: 10px;");
console.log("Last child:", last.textContent);
// Sibling navigation
const second = first.nextElementSibling;
second.setAttribute("style", "background: #FF9800; color: white; padding: 10px;");
console.log("Second (via nextElementSibling):", second.textContent);
// Parent access
console.log("Parent tag:", second.parentNode.tagName);
console.log("Parent id:", second.parentNode.id);
Script Loading Strategies
Ways to include JavaScript:
🎬 Choose a Loading Strategy:
🛑
Blocking
⏳
Defer
⚡
Async
<script src="app.js"></script>
📍 When do browser events fire?
DOMContentLoaded
HTML fully parsed, DOM ready
window.load
Everything loaded (images, etc.)
⏱️ With blocking : DOMContentLoaded waits for script to finish
HTML Parsing
Blocked
Download
Execute
🛑 Blocking Script (Default)
How it works: HTML parsing stops, script downloads and executes, then parsing resumes.
❌ Blocks page rendering
❌ Slows down page load
✅ Scripts execute in order
⚠️ Use only when script must run before DOM
Best for: Critical scripts that must modify the page before it renders (rare).
Events: How JavaScript Listens to the Browser
Events are signals the browser sends when something happens — a click, key press, page load, etc. Your code can "listen" and respond.
🎯 The Basics
📋 Event Types
📦 Event Object
🌊 Event Flow
🎪 Delegation
🎯 What is an Event?
An event is the browser saying: "Hey, something just happened!" — a click, a keypress, the page loading, etc.
📝 How to Listen for Events
<button onclick="alert('Hi')">Click</button>
Mixes HTML with JavaScript
Only ONE handler per event
Hard to debug & maintain
element.addEventListener("click", myFunction)
Clean separation of HTML/JS
Add multiple handlers
Can remove listeners later
🔴 Live Demo - Try It!
👁️ Show Code
// 1. Get references to elements
const likeBtn = document.getElementById ('like-btn' );
const countBtn = document.getElementById ('count-btn' );
const nameInput = document.getElementById ('name-input' );
// 2. Like Button - Toggle on click
let isLiked = false ;
likeBtn.addEventListener ('click' , () => {
isLiked = !isLiked;
likeBtn.textContent = isLiked ? '❤️ Liked!' : '🤍 Like' ;
});
// 3. Count Button - Increment on click
let count = 0 ;
countBtn.addEventListener ('click' , () => {
count++;
countBtn.textContent = `Clicked: ${count} ` ;
});
// 4. Input - Real-time typing with 'input' event
nameInput.addEventListener ('input' , (e) => {
console.log ('User typed:' , e.target.value);
});
// 5. Focus & Blur events
nameInput.addEventListener ('focus' , () => console.log ('Input focused!' ));
nameInput.addEventListener ('blur' , () => console.log ('Input lost focus' ));
💡 Key Syntax:
element.addEventListener("eventType" , callbackFunction )
📋 Common Event Types
🖱️ Mouse Events
click
dblclick
mouseenter
mouseleave
mousemove
contextmenu
⌨️ Keyboard Events
keydown
keyup
keypress
📝 Form Events
submit
change
input
focus
blur
🌐 Page Events
DOMContentLoaded
load
scroll
resize
🔴 Try Different Events!
👁️ Show Code
// Get reference to elements
const input = document.getElementById ('event-input' );
const output = document.getElementById ('types-output' );
// Helper function to log events
function log (type, detail) {
output.innerHTML = `<span> ${type} - ${detail} </span>` + output.innerHTML;
}
// 🖱️ Mouse Events
input.addEventListener ('click' , () => log ('click' , 'Input clicked' ));
input.addEventListener ('dblclick' , () => log ('dblclick' , 'Double clicked!' ));
// ⌨️ Keyboard Events
input.addEventListener ('keydown' , (e) => {
log ('keydown' , `Key: ${e.key} ` );
});
// 📝 Form Events
input.addEventListener ('input' , (e) => {
log ('input' , `Value: " ${e.target.value} "` );
});
input.addEventListener ('focus' , () => log ('focus' , 'Input focused' ));
input.addEventListener ('blur' , () => log ('blur' , 'Input lost focus' ));
// 🌐 Page Events
window.addEventListener ('scroll' , () => {
log ('scroll' , `scrollY: ${window.scrollY} px` );
});
window.addEventListener ('resize' , () => {
log ('resize' , ` ${innerWidth} x ${innerHeight} ` );
});
📦 The Event Object
Every handler receives an event object with useful info:
e.target
The element that triggered the event
e.currentTarget
The element the listener is attached to
e.type
Event type ("click", "keydown", etc.)
e.preventDefault()
Stop default browser behavior
e.stopPropagation()
Stop event from bubbling up
e.key
Which key was pressed (keyboard)
e.clientX / clientY
Mouse position (viewport)
🔴 Inspect the Event Object
👁️ Show Code
Click to Inspect Event
type: -
target: -
clientX: -
clientY: -
timeStamp: -
// Every event handler receives an event object
const button = document.getElementById ('inspect-btn' );
button.addEventListener ('click' , (e) => {
// e.type - The event type
console.log (e.type); // "click"
// e.target - The element that was clicked
console.log (e.target); // <button>
// e.clientX / e.clientY - Mouse position
console.log (e.clientX); // 688 (pixels from left)
console.log (e.clientY); // 778 (pixels from top)
// e.timeStamp - When event occurred
console.log (e.timeStamp); // 48444 (ms since page load)
// Useful methods:
e.preventDefault (); // Stop default action (e.g., form submit)
e.stopPropagation (); // Stop event from bubbling up
});
🌊 Event Flow: Capturing & Bubbling
When you click an element, the event travels through the DOM in 3 phases :
1
CAPTURE
↓ Down
From window down to target
2
TARGET
●
At the clicked element
3
BUBBLE
↑ Up
From target up to window
🤔 Why would you use Capture Phase?
Capture lets you intercept events before they reach the target. Think of it like a security guard checking visitors before they enter a building:
📋 Use Case 1: Validation
Parent can validate or cancel events before children handle them
📋 Use Case 2: Logging
Track all clicks from the top before they reach their targets
📋 Use Case 3: Focus Trap
Modal dialogs can capture focus events to keep focus inside
💡 99% of the time you'll use bubbling (default). Capture is for special cases where you need to act first.
🔴 Click the Inner Box - Watch the Flow!
👁️ Show Code
OUTER (grandparent)
MIDDLE (parent)
INNER (target)
Use Capture Phase
Stop at INNER (stopPropagation)
Clear Log
↑ Bubbling: stopPropagation() on INNER prevents MIDDLE and OUTER from receiving the event.
🎪 Event Delegation
Instead of adding listeners to many children, add ONE listener to the parent!
// 100 buttons = 100 listeners 😰
buttons.forEach(btn => {
btn.addEventListener("click", handle);
});
// 1 listener handles all! 🎉
container.addEventListener("click", e => {
if (e.target.matches("button")) {
handle(e.target);
}
});
✅ Less memory used
✅ Works on dynamic elements
✅ Easier cleanup
🔴 Add Items - They Work Without New Listeners!
👁️ Show Code
+ Add Item
Click items or × to delete (using delegation!)
// Get the parent container (NOT individual items)
const list = document.getElementById ('delegation-list' );
// ONE listener on the parent handles ALL children!
list.addEventListener ('click' , (e) => {
// Check what was actually clicked using e.target
if (e.target.matches ('.delete-btn' )) {
// Delete button was clicked
e.target.parentElement.remove ();
console.log ('Deleted!' );
}
else if (e.target.tagName === 'LI' ) {
// List item was clicked
console.log ('Selected:' , e.target.textContent);
}
});
// Adding new items - they automatically work!
function addItem () {
const li = document.createElement ('li' );
li.innerHTML = 'New Item <button class="delete-btn">×</button>' ;
list.appendChild (li);
// No need to add new listener! Parent already handles it.
}
// Key methods for delegation:
// e.target - the actual clicked element
// e.target.matches('.class') - check if element matches selector
// e.target.closest('.class') - find closest ancestor matching selector
AJAX with XMLHttpRequest (XHR)
XHR predates fetch; still useful for progress events & legacy code. Prefer async; synchronous XHR blocks the UI thread.
📡 XHR Lifecycle - 5 Steps
STEP 1
Create
new XMLHttpRequest()
→
STEP 2
Configure
xhr.open(method, url)
→
STEP 3
Set Options
xhr.responseType
→
STEP 4
Add Listeners
xhr.addEventListener()
→
🎯 XHR Events
load - Success
error - Network fail
progress - Downloading
loadend - Finished
timeout - Too slow
abort - Cancelled
📋 Setting Request Headers
Use setRequestHeader(name, value) after open() but before send()
JSON Data
xhr.setRequestHeader("Content-Type", "application/json")
Form Data
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
Authorization
xhr.setRequestHeader("Authorization", "Bearer token123")
Custom Header
xhr.setRequestHeader("X-Custom-Header", "value")
📤 Sending Data with send()
📭 No Data (GET requests)
xhr.send(); xhr.send(null);
📦 JSON Data (POST/PUT)
const data = { name: "John", age: 25 }; xhr.send(JSON.stringify(data));
📝 FormData (File uploads)
const formData = new FormData(); formData.append("file", fileInput.files[0]); xhr.send(formData);
🔗 URL Encoded
xhr.send("name=John&age=25");
✅
Async (Recommended)
xhr.open("GET", url, true );
Non-blocking
UI stays responsive
Uses event listeners
⛔
Sync (Avoid!)
xhr.open("GET", url, false );
Blocks browser
UI freezes
Deprecated in main thread
📝 Full Async Example
Copy Try it // STEP 1: Create XHR object
const xhr = new XMLHttpRequest();
// STEP 2: Configure request - open(method, url, async)
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", true);
// STEP 3: Set response type
xhr.responseType = "json";
// STEP 4: Add event listeners
xhr.addEventListener("load", () => {
if (xhr.status === 200) {
console.log("✅ Success:", xhr.response.title);
} else {
console.log("❌ Error:", xhr.status);
}
});
xhr.addEventListener("error", () => console.log("❌ Network error!"));
// STEP 5: Send the request
xhr.send();
⚠️ Sync Example (Not Recommended)
Copy Try it // ⚠️ SYNCHRONOUS - Browser freezes until complete!
const xhr = new XMLHttpRequest();
// async = FALSE makes it synchronous (blocking)
xhr.open("GET", "https://jsonplaceholder.typicode.com/posts/1", false);
// Code WAITS here - no event listeners needed
xhr.send();
// Runs only after response arrives
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
console.log("📦 Title:", data.title);
}
// ❌ UI was frozen the entire time!
console.log("💡 Always use async (true) instead!");
Migration tip: Modern code usually uses fetch() + Promises instead of XHR for simpler APIs.
From Callback Hell to Modern Fetch
❌ XHR Sync
😰 Callbacks
✨ async/await
⚡ Promise.all
👆 Click a button to compare approaches...
❌ XHR Sync
😰 Callback Hell
🔗 Promise Chain
✨ async/await
⚡ Promise.all
⚠️
XHR Sync blocks the entire UI!
The browser freezes completely — user cannot scroll, click, or interact with anything until the request completes. This is deprecated and should never be used in production!
Copy // 🚫 XHR SYNCHRONOUS: NEVER USE THIS!
// The third parameter "false" makes it synchronous
// 📚 Note: We write 10 explicit calls for clarity
// Using DummyJSON API - fetching product prices as random numbers
const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;
const xhr1 = new XMLHttpRequest();
xhr1.open("GET", getAPI(), false); xhr1.send();
const n1 = Math.round(JSON.parse(xhr1.responseText).price);
const xhr2 = new XMLHttpRequest();
xhr2.open("GET", getAPI(), false); xhr2.send();
const n2 = Math.round(JSON.parse(xhr2.responseText).price);
const xhr3 = new XMLHttpRequest();
xhr3.open("GET", getAPI(), false); xhr3.send();
const n3 = Math.round(JSON.parse(xhr3.responseText).price);
// ... (n4 through n9 same pattern) ...
const xhr10 = new XMLHttpRequest();
xhr10.open("GET", getAPI(), false); xhr10.send();
const n10 = Math.round(JSON.parse(xhr10.responseText).price);
const sum = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10;
console.log("Sum:", sum);
// 🚫 UI was frozen the whole time!
Copy // 😰 CALLBACK HELL: 10 nested callbacks!
// 📚 Note: We show all 10 levels explicitly for clarity
// Using DummyJSON API - fetching product prices as random numbers
const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;
const getRandomAsync = (onSuccess, onFail) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", getAPI(), true);
xhr.onload = () => xhr.status === 200
? onSuccess(Math.round(JSON.parse(xhr.response).price))
: onFail(xhr.status);
xhr.onerror = () => onFail("Network error");
xhr.send();
};
// The pyramid of doom 😱
getRandomAsync(n1 => {
getRandomAsync(n2 => {
getRandomAsync(n3 => {
getRandomAsync(n4 => {
getRandomAsync(n5 => {
getRandomAsync(n6 => {
getRandomAsync(n7 => {
getRandomAsync(n8 => {
getRandomAsync(n9 => {
getRandomAsync(n10 => {
const sum = n1+n2+n3+n4+n5+n6+n7+n8+n9+n10;
console.log("Sum:", sum);
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
}, e => console.error(e));
// ⏱️ Total time: ~2000ms (sequential!)
Copy Try it // 🔗 PROMISE CHAINS: Flat but still sequential!
// 📚 Note: We show all 10 .then() explicitly for clarity
// Using DummyJSON API - fetching product prices as random numbers
const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;
const getRandomFromServer = () => {
return fetch(getAPI())
.then(res => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); })
.then(data => Math.round(data.price));
};
let n1, n2, n3, n4, n5, n6, n7, n8, n9, n10;
getRandomFromServer()
.then(n => { n1 = n; return getRandomFromServer(); })
.then(n => { n2 = n; return getRandomFromServer(); })
.then(n => { n3 = n; return getRandomFromServer(); })
.then(n => { n4 = n; return getRandomFromServer(); })
.then(n => { n5 = n; return getRandomFromServer(); })
.then(n => { n6 = n; return getRandomFromServer(); })
.then(n => { n7 = n; return getRandomFromServer(); })
.then(n => { n8 = n; return getRandomFromServer(); })
.then(n => { n9 = n; return getRandomFromServer(); })
.then(n => {
n10 = n;
const sum = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10;
console.log("Sum:", sum);
})
.catch(err => console.error(err));
// ⏱️ Total time: ~2000ms (still sequential!)
Copy Try it // ✨ ASYNC/AWAIT: Clean but SEQUENTIAL (slow for 10 requests!)
// 📚 Note: We show all 10 await calls explicitly for clarity
// Using DummyJSON API - fetching product prices as random numbers
const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;
const getRandomFromServer = async () => {
const response = await fetch(getAPI());
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
return Math.round(data.price);
};
(async () => {
// ⚠️ Each await WAITS for the previous one!
const n1 = await getRandomFromServer();
const n2 = await getRandomFromServer();
const n3 = await getRandomFromServer();
const n4 = await getRandomFromServer();
const n5 = await getRandomFromServer();
const n6 = await getRandomFromServer();
const n7 = await getRandomFromServer();
const n8 = await getRandomFromServer();
const n9 = await getRandomFromServer();
const n10 = await getRandomFromServer();
const sum = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10;
console.log("Sum:", sum);
})();
// ⏱️ Total time: ~2000ms (10 sequential requests)
Copy Try it // ⚡ PROMISE.ALL: All 10 requests run at the SAME TIME!
// 📚 Note: We show all 10 calls explicitly for clarity
// Using DummyJSON API - fetching product prices as random numbers
const getAPI = () => `https://dummyjson.com/products/${Math.ceil(Math.random()*100)}`;
const getRandomFromServer = async () => {
const response = await fetch(getAPI());
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();
return Math.round(data.price);
};
(async () => {
// 🚀 All 10 requests start simultaneously!
const [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10] = await Promise.all([
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer(),
getRandomFromServer()
]);
const sum = n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10;
console.log("Sum:", sum);
})();
// ⏱️ Total time: ~200ms (all 10 in parallel!)
// 🏆 That's 10× FASTER than sequential!
🔗
Sequential : When each request depends on the previous
⚡
Promise.all : When requests are independent (fastest!)
🛡️
Promise.allSettled : When you want results even if some fail
🏃
Promise.race : When you need only the fastest response