Skip to content

Commit 1a1ae6d

Browse files
committed
added more docs
1 parent bd6dab3 commit 1a1ae6d

10 files changed

Lines changed: 643 additions & 48 deletions

File tree

docs/01-getting-started/introduction.md

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,6 @@ Ready to dive deeper? Proceed to the next page to configure your local developme
9696

9797
```
9898
docs/
99-
├── 03-deep-dive-core/
100-
│ ├── _category_.json
101-
│ ├── closures-and-lexical-scope.md
102-
│ ├── prototype-and-inheritance.md
103-
│ ├── execution-context-and-callstack.md
104-
│ └── this-keyword-explained.md
10599
├── 04-asynchronous-javascript/
106100
│ ├── _category_.json
107101
│ ├── event-loop-and-task-queue.md

docs/02-javascript-fundamentals/variables-and-scope.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Variables declared outside any function or block belong to the global scope.
5353

5454
:::note
5555

56-
When you run the above code, the output is undefined because the variable `globalAppTitle` is declared in the global scope and is accessible inside the function `printTitle()`.
56+
In the example above, `globalAppTitle` is declared in the global scope, making it accessible from anywhere in the script, including inside functions like `printTitle()`.
5757

5858
So, when we call `printTitle()`, it logs the value of `globalAppTitle` to the console.
5959

@@ -107,9 +107,9 @@ Try editing the script below to observe how block scope and variable re-assignme
107107

108108
## Best Practices
109109

110-
1. **Default to `const**`: Protect variables from unintended re-assignments.
110+
1. **Default to `const`**: Protect variables from unintended re-assignments.
111111
2. **Use `let` for reassignment**: Use only when values must mutate (e.g., loop counters, accumulators).
112-
3. **Avoid `var**`: Prevent scope-leakage issues and silent hoisting bugs in modern applications.
112+
3. **Avoid `var`**: Prevent scope-leakage issues and silent hoisting bugs in modern applications.
113113

114114
## Knowledge Check
115115

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
---
2+
id: event-loop-and-task-queue
3+
title: "The Event Loop & Task Queue Mechanics"
4+
sidebar_label: Event Loop & Task Queues
5+
sidebar_position: 1
6+
description: "Master the JavaScript Event Loop, asynchronous execution concurrency, Call Stack, Microtask Queue, Macrotask Queue, and microtask starvation."
7+
tags: [javascript, async, event-loop, microtasks, macrotasks, concurrency]
8+
keywords: [javascript, async, event-loop, microtasks, macrotasks, concurrency]
9+
---
10+
11+
import JSEditor from "@site/src/components/js-live-code-editor";
12+
import CodeBlock from "@theme/CodeBlock";
13+
import firstExample from "!!raw-loader!../_scripts/asynchronous-javascript/event-loop-playground.js";
14+
import secondExample from "!!raw-loader!../_scripts/asynchronous-javascript/event-loop-exercise.js";
15+
16+
JavaScript is single-threaded, meaning it can only execute one line of code at a time on its main thread. Despite this limitation, it handles non-blocking asynchronous operations—such as network requests, file I/O, and timers—efficiently through the **Event Loop**.
17+
18+
## Architecture of Asynchronous Execution
19+
20+
To handle asynchronous tasks without freezing the user interface, the JavaScript engine works alongside browser Web APIs (or Node.js C++ bindings) and two distinct execution queues.
21+
22+
```text
23+
JavaScript Asynchronous Architecture
24+
┌─────────────────────────────────────────────────────────────┐
25+
│ Call Stack (Synchronous Execution LIFO) │
26+
└──────────────────────────────┬──────────────────────────────┘
27+
│ Delegation
28+
29+
┌─────────────────────────────────────────────────────────────┐
30+
│ Web APIs (Timers, Fetch HTTP, DOM Events, File Systems) │
31+
└──────────────────────────────┬──────────────────────────────┘
32+
│ Callbacks Ready
33+
34+
┌──────────────────────────────┬──────────────────────────────┐
35+
│ Microtask Queue (High-Priority)│ Macrotask Queue (Task Queue)
36+
│ ├── Promises (.then/catch) │ ├── setTimeout / setInterval │
37+
│ ├── queueMicrotask() │ ├── setImmediate (Node.js) │
38+
│ └── MutationObserver │ └── requestAnimationFrame │
39+
└──────────────┬───────────────┴──────────────┬───────────────┘
40+
│ │
41+
└───────────────┬──────────────┘
42+
│ Event Loop Tick
43+
44+
┌─────────────────────────────────────────────────────────────┐
45+
│ Call Stack (Executed when Call Stack is empty) │
46+
└─────────────────────────────────────────────────────────────┘
47+
48+
```
49+
50+
## Microtasks vs. Macrotasks (Task Priorities)
51+
52+
The Event Loop continuously monitors the **Call Stack**. When the stack is empty, it processes pending callbacks according to a strict priority hierarchy:
53+
54+
| Queue Type | Operations | Execution Rule / Priority |
55+
| --- | --- | --- |
56+
| **Microtask Queue** | `Promise` callbacks, `queueMicrotask()`, `process.nextTick` (Node) | **Highest Priority**: Drained **completely** until empty before any macrotask runs. |
57+
| **Macrotask Queue** | `setTimeout`, `setInterval`, `setImmediate`, I/O, UI Rendering | **Normal Priority**: Processes **one single task** per Event Loop tick, then checks microtasks again. |
58+
59+
## The Event Loop Execution Algorithm
60+
61+
During every cycle ("tick") of the Event Loop, the runtime follows these exact steps:
62+
63+
1. **Execute Synchronous Code**: Process all frames in the Call Stack until it is completely empty.
64+
2. **Drain Microtask Queue**: Process every single microtask currently in the queue. If a microtask schedules another microtask, it is executed in the *same* cycle.
65+
3. **Render UI (Browser Only)**: Perform DOM re-paints and run `requestAnimationFrame` callbacks if needed.
66+
4. **Execute One Macrotask**: Dequeue and run the oldest single task from the Macrotask Queue.
67+
5. **Repeat**: Loop back to step 1.
68+
69+
## Microtask Starvation
70+
71+
Because the Event Loop must drain the **entire** Microtask Queue before yielding execution to macrotasks or UI rendering, continuously enqueuing microtasks will block the main thread indefinitely:
72+
73+
```javascript title="Infinite Microtask Starvation Example"
74+
// WARNING: This recursively starves the Macrotask Queue and freezes the UI!
75+
function infiniteMicrotask() {
76+
Promise.resolve().then(() => {
77+
infiniteMicrotask(); // Enqueues another microtask infinitely
78+
});
79+
}
80+
81+
// infiniteMicrotask(); // Un-commenting will crash/freeze the thread!
82+
83+
```
84+
85+
## Interactive Playground: Tracing Execution Order
86+
87+
Predict the log sequence of synchronous statements, `setTimeout`, and `Promise.then` callbacks:
88+
89+
<JSEditor title="Event Loop Playground" run={true}>
90+
{firstExample}
91+
</JSEditor>
92+
93+
## Best Practices
94+
95+
1. **Use Promises/Microtasks for Instant State Updates**: When you need async operations to resolve immediately before DOM repainting or downstream state changes occurs.
96+
2. **Offload Heavy Loops with `setTimeout`**: Yield execution back to the browser frame engine by breaking intensive computations into macrotask chunks (`setTimeout(fn, 0)`).
97+
3. **Avoid Infinite Microtask Chaining**: Never recursively queue microtasks (`queueMicrotask` or `.then`) without exit conditions; doing so blocks DOM rendering and input events.
98+
99+
100+
## Knowledge Check
101+
102+
### Exercise Requirements:
103+
104+
Determine the exact console output order for the following code snippet:
105+
106+
<JSEditor title="Event Loop Exercise" run={true}>
107+
{secondExample}
108+
</JSEditor>
109+
110+
#### Explanation:
111+
112+
1. Synchronous execution logs `A` and `F`.
113+
2. Microtask Queue processes `C` and `E`.
114+
3. Inside microtask `C`, a new macrotask (`D`) is scheduled behind `B`.
115+
4. Macrotask Queue runs `B` first (oldest macrotask), then runs `D`.
116+
117+
:::success Next Up
118+
Now that you have mastered Event Loop ordering and task queues, proceed to **Promises and Async/Await**!
119+
:::
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
id: fetch-api-and-ajax
3+
title: "Fetch API & Asynchronous HTTP"
4+
sidebar_label: Fetch API & AJAX
5+
sidebar_position: 3
6+
description: "Master asynchronous HTTP requests in JavaScript with the Fetch API, AbortController timeout handling, streaming responses, and proper error handling."
7+
tags: [javascript, async, fetch, ajax, http, abortcontroller, web-apis]
8+
keywords: [javascript, async, fetch, ajax, http, abortcontroller, web-apis]
9+
---
10+
11+
import JSEditor from "@site/src/components/js-live-code-editor";
12+
import CodeBlock from "@theme/CodeBlock";
13+
import firstExample from "!!raw-loader!../_scripts/asynchronous-javascript/live-fetch.js";
14+
15+
Asynchronous JavaScript and XML (**AJAX**) allows web applications to communicate with backend servers asynchronously without reloading the current page. Modern JavaScript applications utilize the native promise-based **Fetch API** for networking.
16+
17+
## Evolution: `XMLHttpRequest` to `fetch()`
18+
19+
Before `fetch()`, asynchronous requests relied on `XMLHttpRequest` (XHR), which required verbose, callback-driven code:
20+
21+
```javascript title="legacy-xhr.js"
22+
const xhr = new XMLHttpRequest();
23+
xhr.open("GET", "https://api.example.com/data");
24+
xhr.onload = function () {
25+
if (xhr.status >= 200 && xhr.status < 300) {
26+
console.log(JSON.parse(xhr.responseText));
27+
}
28+
};
29+
xhr.onerror = function () {
30+
console.error("Network Error");
31+
};
32+
xhr.send();
33+
```
34+
35+
The modern **Fetch API** streamlines networking with standard Promises and cleaner configuration objects:
36+
37+
```javascript title="modern-fetch.js"
38+
// Modern Promise-based Fetch
39+
fetch("https://api.example.com/data")
40+
.then((response) => response.json())
41+
.then((data) => console.log(data))
42+
.catch((error) => console.error("Fetch Error:", error));
43+
```
44+
45+
## Configuring Requests & Headers
46+
47+
The `fetch()` function accepts two arguments: the target `resource` URL and an optional `options` configuration object.
48+
49+
```javascript title="fetch-config.js"
50+
async function createUser(userData) {
51+
const response = await fetch("https://api.example.com/users", {
52+
method: "POST", // HTTP Method: GET, POST, PUT, DELETE, PATCH
53+
headers: {
54+
"Content-Type": "application/json",
55+
"Authorization": "Bearer YOUR_JWT_TOKEN"
56+
},
57+
body: JSON.stringify(userData), // Serialize JavaScript object to JSON
58+
mode: "cors", // cors, no-cors, or same-origin
59+
cache: "no-cache"
60+
});
61+
62+
return await response.json();
63+
}
64+
65+
```
66+
67+
## The Fetch Error-Handling Gotcha
68+
69+
Unlike HTTP libraries like Axios, `fetch()` **does not reject** its Promise on HTTP error status codes (such as `404 Not Found` or `500 Internal Server Error`). A `fetch()` Promise only rejects on network failures or blocked requests.
70+
71+
To handle HTTP errors properly, check the `response.ok` boolean property (`status` between 200–299):
72+
73+
```javascript title="safe-fetch.js"
74+
async function safeFetch(url) {
75+
try {
76+
const response = await fetch(url);
77+
78+
// Check for HTTP error status codes (4xx, 5xx)
79+
if (!response.ok) {
80+
throw new Error(`HTTP Error! Status: ${response.status} ${response.statusText}`);
81+
}
82+
83+
const data = await response.json();
84+
return data;
85+
} catch (error) {
86+
console.error("Request Failed:", error.message);
87+
}
88+
}
89+
90+
```
91+
92+
## Aborting Requests & Timeouts (`AbortController`)
93+
94+
To cancel ongoing network requests or implement request timeouts, use the native **`AbortController`** interface:
95+
96+
```javascript title="abort-fetch.js"
97+
async function fetchWithTimeout(resource, options = {}) {
98+
const { timeout = 5000 } = options;
99+
100+
// 1. Create an AbortController instance
101+
const controller = new AbortController();
102+
const id = setTimeout(() => controller.abort(), timeout);
103+
104+
try {
105+
const response = await fetch(resource, {
106+
...options,
107+
signal: controller.signal // Connect signal to fetch
108+
});
109+
clearTimeout(id);
110+
return await response.json();
111+
} catch (error) {
112+
if (error.name === "AbortError") {
113+
throw new Error("Request timed out!");
114+
}
115+
throw error;
116+
}
117+
}
118+
119+
```
120+
121+
## Interactive Playground: Live Fetch Explorer
122+
123+
Run the live `fetch()` request below using JSONPlaceholder API:
124+
125+
<JSEditor title="Live Fetch Playground" run={true}>
126+
{firstExample}
127+
</JSEditor>
128+
129+
## Best Practices
130+
131+
1. **Always Check `response.ok`**: Never assume a resolved `fetch()` promise indicates a successful data payload.
132+
2. **Set Request Timeouts**: Wrap network calls with `AbortController` to prevent hanging pending requests on poor connections.
133+
3. **Use Typed Response Parsing**: Match body parsing methods to payloads (`.json()`, `.text()`, `.blob()`, or `.arrayBuffer()`).
134+
135+
## Knowledge Check
136+
137+
### Exercise Requirements:
138+
139+
Write a reusable function `postJSON(url, payload)` using `async/await` that sends a `POST` request, handles non-2xx HTTP errors properly, and returns the parsed JSON response.
140+
141+
```javascript title="solution.js"
142+
async function postJSON(url, payload) {
143+
const response = await fetch(url, {
144+
method: "POST",
145+
headers: {
146+
"Content-Type": "application/json"
147+
},
148+
body: JSON.stringify(payload)
149+
});
150+
151+
if (!response.ok) {
152+
throw new Error(`Failed to POST to ${url} - Status: ${response.status}`);
153+
}
154+
155+
return await response.json();
156+
}
157+
158+
```
159+
160+
:::success Phase 04 Complete!
161+
Congratulations! You have completed **Phase 04: Asynchronous JavaScript**. Proceed to **Phase 05: DOM & Browser APIs** to build interactive Web applications!
162+
:::

0 commit comments

Comments
 (0)