JSON (JavaScript Object Notation) is a text format for structured data. JSON supports objects, arrays, strings, numbers, booleans, and Example JSON: {
"id": 17,
"name": "Amina",
"active": true,
"roles": ["student", "editor"]
}The JavaScript object and JSON text are related but not identical. 7. Fetch with JSONThe Fetch API returns a promise for a async function loadProducts() {
const response = await fetch("/api/products");
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
const products = await response.json();
return products;
}A critical detail is that A complete request with error handling might be written as follows: async function loadProducts() {
try {
const response = await fetch("/api/products", {
method: "GET",
headers: {
"Accept": "application/json"
}
});
if (!response.ok) {
throw new Error(`Server returned ${response.status}`);
}
const data = await response.json();
if (!Array.isArray(data)) {
throw new Error("Unexpected response format");
}
return data;
} catch (error) {
console.error("Product loading failed:", error);
throw error;
}
}For a JSON POST request: async function createProduct(product) {
const response = await fetch("/api/products", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
},
body: JSON.stringify(product)
});
if (!response.ok) {
throw new Error(`Creation failed: ${response.status}`);
}
return response.json();
}The server must validate the submitted data. Client-side validation improves usability but cannot be treated as a security boundary. Failure categoriesA robust application distinguishes several failures:
Requests can be cancelled with async function loadWithCancellation(signal) {
const response = await fetch("/api/report", { signal });
if (!response.ok) throw new Error("Report request failed");
return response.json();
}
const controller = new AbortController();
loadWithCancellation(controller.signal).catch(error => {
if (error.name !== "AbortError") console.error(error);
});
// Later, for example when leaving the page:
controller.abort();User-facing error messages should be useful without exposing secrets, stack traces, database details, or internal server structure. Logging should also avoid passwords, access tokens, and unnecessary personal data. 8. Browser StorageBrowser storage allows a website to retain information between interactions. The correct mechanism depends on duration, transmission requirements, sensitivity, and scope. CookiesCookies are small name-value data items associated with a domain and path. They are automatically included in matching HTTP requests, subject to cookie rules. Servers commonly use cookies for sessions, preferences, and security controls. Important cookie attributes include:
A server can set a cookie with an HTTP response header. JavaScript can access non-
|
| Feature | Cookies | localStorage | sessionStorage |
|---|---|---|---|
| Automatically sent to server | Yes, when applicable | No | No |
| Typical lifetime | Configurable | Persistent | Tab session |
| JavaScript access | Unless HttpOnly | Yes | Yes |
| Stores | Text, small data | Strings | Strings |
| Best examples | Sessions, server preferences | Non-sensitive preferences | Temporary tab state |
The Web Storage APIs are synchronous and provide no built-in encryption. Any JavaScript running in the origin can usually read them. Therefore, an access token in localStorage may be exposed if the site suffers a cross-site scripting vulnerability. Sensitive authentication designs often prefer secure, HttpOnly, SameSite cookies managed by the server, although the correct choice depends on the architecture and threat model.
Storage decisions should follow data minimization: collect and retain only what the application needs. Developers should identify whether data is personal, sensitive, confidential, or merely functional. They should communicate purposes clearly and follow applicable laws, institutional policies, and consent requirements.
Important practices include:
Secure, HttpOnly, and SameSite attributes;Cross-origin requests are controlled by browser security policies. Cross-Origin Resource Sharing (CORS) allows a server to state which origins may access selected responses. CORS is not a replacement for authentication or authorization. A server must still verify identity and permissions.
Consider an illustrative course dashboard that displays a learner’s profile, enrolled modules, and recent announcements. It should load data from an API, remember the preferred display theme, and show useful messages when the network is unavailable.
The first implementation makes three requests one after another, stores the user profile in localStorage, and assumes every response is successful. It is slow, may display stale personal data, and provides no meaningful failure handling.
The profile, modules, and announcements are independent requests, so they can be initiated together. The theme is a low-risk preference and is suitable for localStorage. The profile should not be cached indefinitely without considering privacy and freshness. The interface should distinguish a temporary network failure from an unauthorized response.
const themeKey = "course-dashboard-theme";
function applyTheme() {
const theme = localStorage.getItem(themeKey) || "light";
document.documentElement.dataset.theme = theme;
}
async function getJson(url) {
const response = await fetch(url, {
headers: { "Accept": "application/json" }
});
if (!response.ok) {
const error = new Error(`Request failed with ${response.status}`);
error.status = response.status;
throw error;
}
return response.json();
}
async function loadDashboard() {
applyTheme();
const statusElement = document.querySelector("#status");
statusElement.textContent = "Loading dashboard…";
try {
const [profile, modules, announcements] = await Promise.all([
getJson("/api/profile"),
getJson("/api/modules"),
getJson("/api/announcements")
]);
renderProfile(profile);
renderModules(modules);
renderAnnouncements(announcements);
statusElement.textContent = "Dashboard loaded.";
} catch (error) {
if (error.status === 401 || error.status === 403) {
statusElement.textContent = "Please sign in to view this dashboard.";
} else {
statusElement.textContent =
"The dashboard could not be loaded. Check your connection and try again.";
}
console.error("Dashboard error", error);
}
}The code uses parallel requests, checks HTTP status explicitly, avoids placing profile data in persistent storage, and gives the user a safe general message. In a production system, the server would control authentication and authorization, and the interface would also address loading states, retries, cancellation, and partial results.
This design reduces unnecessary waiting and separates concerns: getJson() handles transport and parsing, while rendering functions handle presentation. The case demonstrates that asynchronous programming is not merely a syntax choice. It affects responsiveness, failure behavior, privacy, and the overall reliability of the application.
Use one consistent asynchronous style within a function or module. Prefer async/await for multi-step workflows, while understanding promises because the two are closely related. Always handle rejected promises. Check HTTP status codes. Validate response shapes before using them. Avoid unnecessary sequential waits and avoid uncontrolled request bursts.
Storage is not a substitute for a server database. Browser data can be deleted, modified, unavailable, or isolated by privacy features. Quotas vary by browser and context. Web Storage operations can block the main thread. Cookies are transmitted automatically and therefore should remain small and carefully scoped.
Retries require judgment. Retrying a GET may be reasonable after a temporary failure, but blindly retrying a non-idempotent POST can create duplicate records. A retry strategy should use limits, delays, cancellation, and server-supported idempotency where appropriate.
Contemporary applications may also use IndexedDB for larger structured client-side data, service workers for caching and offline behavior, and streaming APIs for incremental responses. These are extensions of the same underlying concerns: lifecycle, failure, consistency, performance, and privacy.
Asynchronous JavaScript enables web applications to remain responsive while waiting for timers, network operations, and other browser services. The event loop coordinates the call stack, host APIs, and queues. Callbacks provide a basic completion mechanism; promises represent eventual success or failure; and async/await offers readable promise-based control flow.
The Fetch API retrieves resources asynchronously. Developers must check both network errors and HTTP status codes, parse JSON carefully, validate response structures, and provide safe user-facing error messages. Promise.all() is useful for independent requests, while sequential await is appropriate when one operation depends on another.
Cookies, localStorage, and sessionStorage differ in lifetime, scope, transmission behavior, and security properties. Sensitive information should not be placed casually in JavaScript-readable storage. Secure application design combines HTTPS, suitable cookie attributes, server-side validation and authorization, data minimization, and privacy-aware retention policies.
Event loop: The mechanism that coordinates JavaScript execution with queued asynchronous work.
Call stack: The structure containing functions currently executing.
Callback: A function supplied to be called later.
Promise: An object representing the eventual result of an asynchronous operation.
Pending: The initial unsettled state of a promise.
Fulfilled: The successful settled state of a promise.
Rejected: The failed settled state of a promise.
Microtask: Queued work, including promise handlers, normally processed before the next ordinary task.
Fetch API: A browser API for making asynchronous network requests.
Response: The object representing an HTTP response returned by fetch().
JSON: A text-based format for structured data exchange.
HTTP status: A server response code indicating the result category of a request.
Cookie: Small data associated with a domain and potentially sent with HTTP requests.
localStorage: Persistent, origin-scoped string storage in the browser.
sessionStorage: Tab-session-scoped string storage in the browser.
CORS: A browser-controlled mechanism for permitting selected cross-origin requests.
HttpOnly: A cookie attribute that prevents ordinary JavaScript access.
SameSite: A cookie attribute controlling cross-site sending behavior.
Data minimization: The practice of collecting and retaining only necessary data.
AbortController: An API used to signal cancellation of operations such as fetch requests.
response.ok after calling fetch()?sessionStorage.HttpOnly cookie attribute provide?async/await, including one advantage and limitation of each.localStorage, and `sessionStorage in terms of lifetime, transmission, access, and appropriate use.Which statement best describes the event loop?
A. It permanently stores data in the browser.
B. It moves eligible queued work to the call stack when JavaScript is ready.
C. It converts JSON into HTML automatically.
D. It guarantees that all network requests finish in order.
Correct Answer: B. It moves eligible queued work to the call stack when JavaScript is ready.
What does an async function return?
A. Always a string
B. A timer identifier
C. A promise
D. A JSON object only
Correct Answer: C. A promise
What normally happens when fetch() receives an HTTP 404 response?
A. The promise always rejects automatically.
B. The browser changes the response to status 200.
C. The promise usually fulfills with a Response whose ok property is false.
D. The response is automatically retried.
Correct Answer: C. The promise usually fulfills with a Response whose ok property is false.
Which method converts a JavaScript object into JSON text?
A. JSON.parse()
B. JSON.stringify()
C. Response.json()
D. Object.toJSONText()
Correct Answer: B. JSON.stringify()
Which Promise method waits for all supplied promises to fulfill and rejects if one rejects?
A. Promise.race()
B. Promise.any()
C. Promise.all()
D. Promise.resolve()
Correct Answer: C. Promise.all()
Which storage mechanism is normally scoped to a browser tab session?
A. sessionStorage
B. localStorage
C. A permanent cookie only
D. The call stack
Correct Answer: A. sessionStorage
Which cookie attribute prevents ordinary JavaScript from reading the cookie?
A. Secure
B. Path
C. HttpOnly
D. Max-Age
Correct Answer: C. HttpOnly
Why is localStorage generally unsuitable for storing passwords?
A. It cannot store strings.
B. It is readable by JavaScript running in the origin and is not inherently encrypted.
C. It is automatically sent with every HTTP request.
D. It exists only while a tab remains open.
Correct Answer: B. It is readable by JavaScript running in the origin and is not inherently encrypted.
What is a suitable reason to use Promise.all()?
A. To run independent asynchronous operations concurrently and obtain all results.
B. To ensure every request is sent sequentially.
C. To suppress all rejected promises permanently.
D. To convert a response into a cookie.
Correct Answer: A. To run independent asynchronous operations concurrently and obtain all results.
What does AbortController allow a program to do with a fetch request?
A. Change a 404 response into a 200 response.
B. Cancel the request by using its signal.
C. Encrypt JSON automatically.
D. Store the response in sessionStorage automatically.
Correct Answer: B. Cancel the request by using its signal.