[{"data":1,"prerenderedAt":2391},["ShallowReactive",2],{"page-\u002Fjs\u002F21-web-storage-and-apis":3},{"id":4,"title":5,"body":6,"description":238,"extension":2385,"meta":2386,"navigation":43,"path":2387,"seo":2388,"stem":2389,"__hash__":2390},"content\u002Fjs\u002F21-web-storage-and-apis.md","21 — Web Storage & APIs",{"type":7,"value":8,"toc":2347},"minimark",[9,13,129,223,404,487,588,771,885,967,1044,1120,1179,1340,1478,1639,1705,1795,2024,2085,2271,2343],[10,11,5],"h1",{"id":12},"_21-web-storage-apis",[14,15,16,30,83],"question-wrapper",{},[17,18,20,21,25,26,29],"h3",{"id":19},"q1-which-statement-correctly-distinguishes-localstorage-from-sessionstorage","Q1. Which statement correctly distinguishes ",[22,23,24],"code",{},"localStorage"," from ",[22,27,28],{},"sessionStorage","?",[31,32,35,52,63,72],"ul",{"className":33},[34],"contains-task-list",[36,37,40,45,46,48,49,51],"li",{"className":38},[39],"task-list-item",[41,42],"input",{"disabled":43,"type":44},true,"checkbox"," ",[22,47,24],{}," data is cleared when the browser closes; ",[22,50,28],{}," persists indefinitely",[36,53,55,45,57,59,60,62],{"className":54},[39],[41,56],{"disabled":43,"type":44},[22,58,24],{}," persists across browser restarts until explicitly cleared; ",[22,61,28],{}," is cleared when the tab closes",[36,64,66,68,69,71],{"className":65},[39],[41,67],{"disabled":43,"type":44}," Both persist indefinitely, but ",[22,70,28],{}," is shared across all tabs of the same origin",[36,73,75,45,77,79,80,82],{"className":74},[39],[41,76],{"disabled":43,"type":44},[22,78,24],{}," is per-tab; ",[22,81,28],{}," is shared across the whole browser",[84,85,86,90,102],"details",{},[87,88,89],"summary",{},"Show Answer",[91,92,93,97,98,59,100,62],"p",{},[94,95,96],"strong",{},"Answer:"," B — ",[22,99,24],{},[22,101,28],{},[91,103,104,45,107,109,110,113,114,117,118,120,121,123,124,128],{},[94,105,106],{},"Explanation:",[22,108,24],{}," has no expiration and survives browser restarts, page reloads, and navigation — it's only removed by explicit ",[22,111,112],{},"removeItem","\u002F",[22,115,116],{},"clear()",", the user clearing site data, or the browser evicting it. ",[22,119,28],{}," is scoped to a single tab's lifetime: closing that tab destroys it, even though a page reload within the same tab preserves it. Option A inverts the two. Option C is wrong because ",[22,122,28],{}," is explicitly ",[125,126,127],"em",{},"not"," shared between tabs, even same-origin ones opened to the same URL — each tab gets its own isolated storage area. Option D is backwards.",[14,130,131,141,172],{},[17,132,134,135,137,138,140],{"id":133},"q2-a-team-stores-a-jwt-auth-token-in-a-cookie-versus-localstorage-which-behavior-is-unique-to-cookies-not-localstorage","Q2. A team stores a JWT auth token in a cookie versus ",[22,136,24],{},". Which behavior is unique to cookies (not ",[22,139,24],{},")?",[31,142,144,150,156,166],{"className":143},[34],[36,145,147,149],{"className":146},[39],[41,148],{"disabled":43,"type":44}," The value is limited to strings",[36,151,153,155],{"className":152},[39],[41,154],{"disabled":43,"type":44}," The value is automatically sent with every same-origin HTTP request to the server (unless flagged otherwise)",[36,157,159,161,162,165],{"className":158},[39],[41,160],{"disabled":43,"type":44}," The value can be read via JavaScript's ",[22,163,164],{},"document.cookie"," or storage APIs",[36,167,169,171],{"className":168},[39],[41,170],{"disabled":43,"type":44}," The value is scoped to a single origin",[84,173,174,176,181],{},[87,175,89],{},[91,177,178,180],{},[94,179,96],{}," B — The value is automatically sent with every same-origin HTTP request to the server (unless flagged otherwise)",[91,182,183,185,186,189,190,189,193,196,197,200,201,203,204,207,208,210,211,214,215,217,218,113,220,222],{},[94,184,106],{}," Cookies are attached to outgoing HTTP requests automatically by the browser (governed by ",[22,187,188],{},"Domain",", ",[22,191,192],{},"Path",[22,194,195],{},"SameSite",", and ",[22,198,199],{},"Secure"," attributes), which is why they're used for session identifiers the server needs to see. ",[22,202,24],{}," is never transmitted automatically — a page must explicitly read it and attach it (e.g., as an ",[22,205,206],{},"Authorization"," header). Option A is wrong because both cookies and ",[22,209,24],{}," only store strings. Option C is wrong because both are readable via JS unless a cookie is marked ",[22,212,213],{},"HttpOnly",", which then hides it from ",[22,216,164],{},". Option D is wrong because both are origin-scoped (cookies also add ",[22,219,188],{},[22,221,192],{}," scoping on top).",[14,224,226,230,315,355],{"language":225},"javascript",[17,227,229],{"id":228},"q3-what-happens-when-you-run-the-following-code","Q3. What happens when you run the following code?",[231,232,233],"code-wrapper",{"language":225},[234,235,239],"pre",{"className":236,"code":237,"language":225,"meta":238,"style":238},"language-javascript shiki shiki-themes github-light github-dark","const user = { name: \"Ravi\", age: 30 };\nlocalStorage.setItem(\"user\", user);\nconsole.log(localStorage.getItem(\"user\"));\n","",[22,240,241,274,293],{"__ignoreMap":238},[242,243,246,250,254,257,261,265,268,271],"span",{"class":244,"line":245},"line",1,[242,247,249],{"class":248},"svdQ7","const",[242,251,253],{"class":252},"snvgF"," user",[242,255,256],{"class":248}," =",[242,258,260],{"class":259},"ssxIu"," { name: ",[242,262,264],{"class":263},"sJ6F3","\"Ravi\"",[242,266,267],{"class":259},", age: ",[242,269,270],{"class":252},"30",[242,272,273],{"class":259}," };\n",[242,275,277,280,284,287,290],{"class":244,"line":276},2,[242,278,279],{"class":259},"localStorage.",[242,281,283],{"class":282},"sIsaT","setItem",[242,285,286],{"class":259},"(",[242,288,289],{"class":263},"\"user\"",[242,291,292],{"class":259},", user);\n",[242,294,296,299,302,305,308,310,312],{"class":244,"line":295},3,[242,297,298],{"class":259},"console.",[242,300,301],{"class":282},"log",[242,303,304],{"class":259},"(localStorage.",[242,306,307],{"class":282},"getItem",[242,309,286],{"class":259},[242,311,289],{"class":263},[242,313,314],{"class":259},"));\n",[31,316,318,328,338,347],{"className":317},[34],[36,319,321,323,324,327],{"className":320},[39],[41,322],{"disabled":43,"type":44}," It logs ",[22,325,326],{},"{ name: \"Ravi\", age: 30 }"," as a live object",[36,329,331,333,334,337],{"className":330},[39],[41,332],{"disabled":43,"type":44}," It throws a ",[22,335,336],{},"TypeError"," because objects can't be stored",[36,339,341,343,344],{"className":340},[39],[41,342],{"disabled":43,"type":44}," It logs the string ",[22,345,346],{},"\"[object Object]\"",[36,348,350,323,352],{"className":349},[39],[41,351],{"disabled":43,"type":44},[22,353,354],{},"undefined",[84,356,357,359,366],{},[87,358,89],{},[91,360,361,363,364],{},[94,362,96],{}," C — It logs the string ",[22,365,346],{},[91,367,368,370,371,373,374,377,378,380,381,384,385,388,389,392,393,396,397,400,401,403],{},[94,369,106],{}," The Web Storage API only stores strings. ",[22,372,283],{}," coerces any non-string value using ",[22,375,376],{},"String(value)",", and the default string conversion of a plain object is ",[22,379,346],{}," (via ",[22,382,383],{},"Object.prototype.toString","), silently discarding the actual data. ",[94,386,387],{},"Idiom:"," always ",[22,390,391],{},"JSON.stringify"," before storing and ",[22,394,395],{},"JSON.parse"," after reading — there's no error to warn you otherwise, which makes this a common silent-data-loss bug. Option B is tempting because it feels like it ",[125,398,399],{},"should"," error, but ",[22,402,283],{}," never validates the value's type, it just stringifies it.",[14,405,406,418,450],{},[17,407,409,410,413,414,417],{"id":408},"q4-when-does-the-storage-event-fire-on-the-window-object","Q4. When does the ",[22,411,412],{},"storage"," event fire on the ",[22,415,416],{},"window"," object?",[31,419,421,427,433,444],{"className":420},[34],[36,422,424,426],{"className":423},[39],[41,425],{"disabled":43,"type":44}," In every tab, including the one that made the change",[36,428,430,432],{"className":429},[39],[41,431],{"disabled":43,"type":44}," Only in other tabs\u002Fwindows of the same origin, not the tab that made the change",[36,434,436,438,439,441,442],{"className":435},[39],[41,437],{"disabled":43,"type":44}," Only when ",[22,440,28],{}," changes, never for ",[22,443,24],{},[36,445,447,449],{"className":446},[39],[41,448],{"disabled":43,"type":44}," Only when the page is reloaded",[84,451,452,454,459],{},[87,453,89],{},[91,455,456,458],{},[94,457,96],{}," B — Only in other tabs\u002Fwindows of the same origin, not the tab that made the change",[91,460,461,463,464,466,467,469,470,472,473,476,477,113,479,113,481,483,484,486],{},[94,462,106],{}," The ",[22,465,412],{}," event is the browser's cross-tab notification mechanism for ",[22,468,24],{}," changes — it fires on ",[22,471,416],{}," in every ",[125,474,475],{},"other"," document sharing that origin, but never in the document that actually called ",[22,478,283],{},[22,480,112],{},[22,482,116],{},". This is a common gotcha when trying to sync UI state within the same tab: you must update that tab's UI manually since it won't receive its own event. Option A is the tempting-but-wrong assumption. Option C is wrong — ",[22,485,28],{}," changes don't fire the storage event at all across tabs since it isn't shared. Option D is unrelated to the trigger condition.",[14,488,489,497,538],{},[17,490,492,493,496],{"id":491},"q5-what-does-fetch-return","Q5. What does ",[22,494,495],{},"fetch()"," return?",[31,498,500,506,520,528],{"className":499},[34],[36,501,503,505],{"className":502},[39],[41,504],{"disabled":43,"type":44}," The parsed JSON body directly",[36,507,509,511,512,515,516,519],{"className":508},[39],[41,510],{"disabled":43,"type":44}," A ",[22,513,514],{},"Promise"," that resolves to a ",[22,517,518],{},"Response"," object",[36,521,523,511,525,527],{"className":522},[39],[41,524],{"disabled":43,"type":44},[22,526,518],{}," object synchronously",[36,529,531,533,534,537],{"className":530},[39],[41,532],{"disabled":43,"type":44}," An ",[22,535,536],{},"XMLHttpRequest"," instance",[84,539,540,542,551],{},[87,541,89],{},[91,543,544,546,547,515,549,519],{},[94,545,96],{}," B — A ",[22,548,514],{},[22,550,518],{},[91,552,553,45,555,558,559,562,563,565,566,569,570,573,574,576,577,580,581,584,585,587],{},[94,554,106],{},[22,556,557],{},"fetch(url)"," immediately returns a ",[22,560,561],{},"Promise\u003CResponse>",". The ",[22,564,518],{}," object wraps headers, status, and a body stream — you must call a method like ",[22,567,568],{},".json()"," or ",[22,571,572],{},".text()"," (which itself returns another ",[22,575,514],{},") to extract the actual payload, meaning a full fetch-and-parse is typically two ",[22,578,579],{},"await","s. Option A is a common beginner shortcut mistake — assuming ",[22,582,583],{},"fetch"," parses JSON for you like some HTTP client libraries do. Option C ignores that network calls are inherently asynchronous. Option D confuses ",[22,586,583],{}," with the older callback\u002Fevent-based API it was designed to replace.",[14,589,590,602,674,683,719],{"language":225},[17,591,593,594,597,598,601],{"id":592},"q6-a-developer-writes-the-following-and-is-confused-why-the-catch-block-never-runs-for-a-404-response","Q6. A developer writes the following and is confused why the ",[22,595,596],{},"catch"," block never runs for a ",[22,599,600],{},"404"," response:",[231,603,604],{"language":225},[234,605,607],{"className":236,"code":606,"language":225,"meta":238,"style":238},"fetch(\"\u002Fapi\u002Fusers\u002F999\")\n  .then(res => res.json())\n  .catch(err => console.error(\"Request failed:\", err));\n",[22,608,609,621,647],{"__ignoreMap":238},[242,610,611,613,615,618],{"class":244,"line":245},[242,612,583],{"class":282},[242,614,286],{"class":259},[242,616,617],{"class":263},"\"\u002Fapi\u002Fusers\u002F999\"",[242,619,620],{"class":259},")\n",[242,622,623,626,629,631,635,638,641,644],{"class":244,"line":276},[242,624,625],{"class":259},"  .",[242,627,628],{"class":282},"then",[242,630,286],{"class":259},[242,632,634],{"class":633},"sCrzJ","res",[242,636,637],{"class":248}," =>",[242,639,640],{"class":259}," res.",[242,642,643],{"class":282},"json",[242,645,646],{"class":259},"())\n",[242,648,649,651,653,655,658,660,663,666,668,671],{"class":244,"line":295},[242,650,625],{"class":259},[242,652,596],{"class":282},[242,654,286],{"class":259},[242,656,657],{"class":633},"err",[242,659,637],{"class":248},[242,661,662],{"class":259}," console.",[242,664,665],{"class":282},"error",[242,667,286],{"class":259},[242,669,670],{"class":263},"\"Request failed:\"",[242,672,673],{"class":259},", err));\n",[91,675,676,677,679,680,682],{},"Why doesn't a ",[22,678,600],{}," trigger the ",[22,681,596],{}," block?",[31,684,686,694,702,710],{"className":685},[34],[36,687,689,45,691,693],{"className":688},[39],[41,690],{"disabled":43,"type":44},[22,692,583],{}," only rejects on network failure (e.g., DNS error, offline), not on HTTP error status codes like 404 or 500",[36,695,697,45,699,701],{"className":696},[39],[41,698],{"disabled":43,"type":44},[22,700,600],{}," responses are automatically retried, so the error is swallowed",[36,703,705,45,707,709],{"className":704},[39],[41,706],{"disabled":43,"type":44},[22,708,568],{}," silently ignores error status codes",[36,711,713,715,716,718],{"className":712},[39],[41,714],{"disabled":43,"type":44}," This is a bug in the code; ",[22,717,583],{}," should reject but doesn't due to a browser inconsistency",[84,720,721,723,730],{},[87,722,89],{},[91,724,725,727,728,693],{},[94,726,96],{}," A — ",[22,729,583],{},[91,731,732,734,735,737,738,113,741,744,745,748,749,751,752,755,756,759,760,762,763,766,767,770],{},[94,733,106],{}," By design, ",[22,736,583],{},"'s promise only rejects for genuine network-level failures — a ",[22,739,740],{},"4xx",[22,742,743],{},"5xx"," response is still a ",[125,746,747],{},"successful"," HTTP exchange as far as ",[22,750,583],{}," is concerned, so it resolves normally with ",[22,753,754],{},"response.ok === false"," and the appropriate ",[22,757,758],{},"response.status",". This is one of the most common ",[22,761,583],{}," gotchas and a real source of silently-swallowed errors in production: code that assumes \"no exception means success\" will happily try to parse an error page's body as JSON. ",[94,764,765],{},"Debug:"," the fix is to explicitly check ",[22,768,769],{},"if (!res.ok) throw new Error(...)"," before parsing. Option B and C are fabricated behaviors; option D incorrectly frames intentional spec behavior as a bug.",[14,772,773,785,825],{},[17,774,776,777,780,781,784],{"id":775},"q7-what-is-the-key-advantage-of-structuredcloneobj-over-jsonparsejsonstringifyobj-for-deep-copying-data","Q7. What is the key advantage of ",[22,778,779],{},"structuredClone(obj)"," over ",[22,782,783],{},"JSON.parse(JSON.stringify(obj))"," for deep-copying data?",[31,786,788,794,813,819],{"className":787},[34],[36,789,791,793],{"className":790},[39],[41,792],{"disabled":43,"type":44}," It is always faster in every browser",[36,795,797,799,800,189,803,189,806,196,809,812],{"className":796},[39],[41,798],{"disabled":43,"type":44}," It can clone richer types like ",[22,801,802],{},"Date",[22,804,805],{},"Map",[22,807,808],{},"Set",[22,810,811],{},"ArrayBuffer"," correctly, and preserves circular references",[36,814,816,818],{"className":815},[39],[41,817],{"disabled":43,"type":44}," It can clone functions and DOM nodes without error",[36,820,822,824],{"className":821},[39],[41,823],{"disabled":43,"type":44}," It converts numbers to strings for safe transport",[84,826,827,829,842],{},[87,828,89],{},[91,830,831,833,834,189,836,189,838,196,840,812],{},[94,832,96],{}," B — It can clone richer types like ",[22,835,802],{},[22,837,805],{},[22,839,808],{},[22,841,811],{},[91,843,844,45,846,848,849,851,852,113,854,856,857,189,860,862,863,865,866,869,870,873,874,876,877,880,881,884],{},[94,845,106],{},[22,847,391],{}," silently mangles many types: a ",[22,850,802],{}," becomes a string, a ",[22,853,805],{},[22,855,808],{}," becomes ",[22,858,859],{},"{}",[22,861,354],{}," values are dropped, and a circular reference throws a ",[22,864,336],{},". ",[22,867,868],{},"structuredClone"," uses the structured clone algorithm (the same one browsers use for ",[22,871,872],{},"postMessage","), which correctly round-trips these types and can even clone objects containing circular references back into an equivalent circular structure. Option C is the tempting trap — ",[22,875,868],{}," explicitly ",[125,878,879],{},"cannot"," clone functions, DOM nodes, or objects with property accessors\u002Fprototypes beyond plain data, and throws a ",[22,882,883],{},"DataCloneError"," if you try. Option A overstates it — performance varies by payload shape. Option D is fabricated.",[14,886,887,895,934],{},[17,888,890,891,894],{"id":889},"q8-a-page-stores-several-megabytes-of-data-over-time-via-repeated-localstoragesetitem-calls-until-the-origins-quota-commonly-510mb-depending-on-browser-is-exceeded-what-happens-on-the-call-that-exceeds-it","Q8. A page stores several megabytes of data over time via repeated ",[22,892,893],{},"localStorage.setItem"," calls until the origin's quota (commonly ~5–10MB depending on browser) is exceeded. What happens on the call that exceeds it?",[31,896,898,904,917,928],{"className":897},[34],[36,899,901,903],{"className":900},[39],[41,902],{"disabled":43,"type":44}," The call silently does nothing and older data is evicted automatically",[36,905,907,333,909,912,913,916],{"className":906},[39],[41,908],{"disabled":43,"type":44},[22,910,911],{},"DOMException"," (commonly named ",[22,914,915],{},"QuotaExceededError",") synchronously",[36,918,920,463,922,924,925,927],{"className":919},[39],[41,921],{"disabled":43,"type":44},[22,923,514],{}," returned by ",[22,926,283],{}," rejects",[36,929,931,933],{"className":930},[39],[41,932],{"disabled":43,"type":44}," The browser prompts the user to grant more space",[84,935,936,938,947],{},[87,937,89],{},[91,939,940,942,943,912,945,916],{},[94,941,96],{}," B — It throws a ",[22,944,911],{},[22,946,915],{},[91,948,949,45,951,953,954,956,957,959,960,962,963,966],{},[94,950,106],{},[22,952,893],{}," is a synchronous API, so quota overflow is reported synchronously by throwing — it does not return a rejected promise (there is no promise at all) and it does not silently evict old data like an LRU cache would. ",[94,955,765],{}," production code writing to ",[22,958,24],{}," in a loop or with user-generated content should wrap ",[22,961,283],{}," in a ",[22,964,965],{},"try\u002Fcatch"," to handle this gracefully instead of crashing the calling code. Option A describes cache-eviction behavior that Web Storage doesn't have. Option C is tempting because so many modern Web APIs are promise-based, but Web Storage predates that convention and stayed synchronous. Option D describes permission-prompt UX that some other APIs (like persistent storage) use, not quota overflow itself.",[14,968,969,983,1018],{},[17,970,972,973,975,976,569,979,982],{"id":971},"q9-why-is-heavy-repeated-use-of-localstorage-inside-a-hot-code-path-eg-on-every-scroll-or-mousemove-event-considered-a-performance-anti-pattern","Q9. Why is heavy, repeated use of ",[22,974,24],{}," inside a hot code path (e.g., on every ",[22,977,978],{},"scroll",[22,980,981],{},"mousemove"," event) considered a performance anti-pattern?",[31,984,986,994,1002,1010],{"className":985},[34],[36,987,989,45,991,993],{"className":988},[39],[41,990],{"disabled":43,"type":44},[22,992,24],{}," operations are always executed on a background thread, so they don't block, but they leak memory over time",[36,995,997,45,999,1001],{"className":996},[39],[41,998],{"disabled":43,"type":44},[22,1000,24],{}," reads and writes are synchronous and block the main thread, so frequent calls can cause jank",[36,1003,1005,45,1007,1009],{"className":1004},[39],[41,1006],{"disabled":43,"type":44},[22,1008,24],{}," triggers a full page reload on every write",[36,1011,1013,45,1015,1017],{"className":1012},[39],[41,1014],{"disabled":43,"type":44},[22,1016,24],{}," writes are asynchronous but rate-limited to one per second by the spec",[84,1019,1020,1022,1028],{},[87,1021,89],{},[91,1023,1024,97,1026,1001],{},[94,1025,96],{},[22,1027,24],{},[91,1029,1030,1032,1033,1035,1036,1039,1040,1043],{},[94,1031,106],{}," Every ",[22,1034,24],{}," read\u002Fwrite happens synchronously on the main thread and, depending on the browser, may involve disk I\u002FO — calling it dozens of times per second inside a scroll or resize handler competes directly with rendering work and can visibly stutter the UI. ",[94,1037,1038],{},"Performance:"," the idiomatic fix is to debounce\u002Fthrottle the writes, batch them, or move to ",[22,1041,1042],{},"IndexedDB"," (which is asynchronous) for high-frequency or large-payload storage needs. Option A and D invent async\u002Fthreading behavior Web Storage doesn't have. Option C is simply false — writes don't reload the page.",[14,1045,1046,1053,1086],{},[17,1047,1049,1050,1052],{"id":1048},"q10-a-user-opens-the-same-web-app-in-two-separate-tabs-they-interact-with-tab-a-which-writes-to-sessionstorage-what-does-tab-b-see","Q10. A user opens the same web app in two separate tabs. They interact with Tab A, which writes to ",[22,1051,28],{},". What does Tab B see?",[31,1054,1056,1065,1074,1080],{"className":1055},[34],[36,1057,1059,1061,1062,1064],{"className":1058},[39],[41,1060],{"disabled":43,"type":44}," Tab B sees the same ",[22,1063,28],{}," values immediately, since both tabs share the same origin",[36,1066,1068,1070,1071,1073],{"className":1067},[39],[41,1069],{"disabled":43,"type":44}," Tab B has its own independent ",[22,1072,28],{},", unaffected by Tab A's writes",[36,1075,1077,1079],{"className":1076},[39],[41,1078],{"disabled":43,"type":44}," Tab B sees the values only after Tab A is closed",[36,1081,1083,1085],{"className":1082},[39],[41,1084],{"disabled":43,"type":44}," Tab B sees the values only after both tabs are refreshed",[84,1087,1088,1090,1097],{},[87,1089,89],{},[91,1091,1092,1094,1095,1073],{},[94,1093,96],{}," B — Tab B has its own independent ",[22,1096,28],{},[91,1098,1099,1101,1102,1104,1105,1107,1108,1110,1111,1113,1114,1116,1117,1119],{},[94,1100,106],{}," Unlike ",[22,1103,24],{},", which is shared across every tab\u002Fwindow of the same origin, ",[22,1106,28],{}," is scoped per top-level browsing context (roughly: per tab). Even two tabs pointed at the identical URL of the identical origin get separate, isolated ",[22,1109,28],{}," areas — the only exception is that a duplicated tab (e.g., \"duplicate tab\" from the browser menu) inherits a copy of the original's ",[22,1112,28],{}," at the moment of duplication. Option A confuses it with ",[22,1115,24],{},"'s sharing behavior. Options C and D fabricate a sync mechanism that doesn't exist for ",[22,1118,28],{},".",[14,1121,1122,1126,1153],{},[17,1123,1125],{"id":1124},"q11-why-do-teams-generally-avoid-putting-large-amounts-of-data-in-cookies-beyond-the-4kb-per-cookie-size-limit","Q11. Why do teams generally avoid putting large amounts of data in cookies, beyond the ~4KB per-cookie size limit?",[31,1127,1129,1135,1141,1147],{"className":1128},[34],[36,1130,1132,1134],{"className":1131},[39],[41,1133],{"disabled":43,"type":44}," Cookies are readable by any origin, not just the one that set them",[36,1136,1138,1140],{"className":1137},[39],[41,1139],{"disabled":43,"type":44}," Every cookie for a domain is sent with every matching HTTP request to that domain, adding latency and bandwidth overhead to unrelated requests (e.g., image loads)",[36,1142,1144,1146],{"className":1143},[39],[41,1145],{"disabled":43,"type":44}," Cookies cannot store string data, only numbers",[36,1148,1150,1152],{"className":1149},[39],[41,1151],{"disabled":43,"type":44}," Browsers cap total cookies per domain at 3",[84,1154,1155,1157,1162],{},[87,1156,89],{},[91,1158,1159,1161],{},[94,1160,96],{}," B — Every cookie for a domain is sent with every matching HTTP request to that domain, adding latency and bandwidth overhead to unrelated requests (e.g., image loads)",[91,1163,1164,1166,1167,1170,1171,113,1173,1175,1176,1178],{},[94,1165,106],{}," Because the browser auto-attaches all applicable cookies to ",[125,1168,1169],{},"every"," request to that origin\u002Fpath — including static asset requests like images and stylesheets — bloated cookies add real, repeated overhead to traffic that has nothing to do with the cookie's purpose. This is exactly why session identifiers (small) belong in cookies while bulk data belongs in ",[22,1172,24],{},[22,1174,1042],{}," (never auto-sent). Option A is false — cross-origin cookie reads are blocked by the same-origin policy (modern ",[22,1177,195],{}," rules restrict this further). Option C is nonsensical since cookies only ever store strings. Option D fabricates a specific count; the real limit is typically around 50–180 cookies per domain depending on the browser, not 3.",[14,1180,1181,1189,1256,1291],{"language":225},[17,1182,1184,1185,1188],{"id":1183},"q12-what-happens-when-you-call-structuredclone-on-an-object-that-contains-a-function-property","Q12. What happens when you call ",[22,1186,1187],{},"structuredClone()"," on an object that contains a function property?",[231,1190,1191],{"language":225},[234,1192,1194],{"className":236,"code":1193,"language":225,"meta":238,"style":238},"const config = {\n  name: \"widget\",\n  onClick: () => console.log(\"clicked\"),\n};\nstructuredClone(config);\n",[22,1195,1196,1208,1219,1242,1248],{"__ignoreMap":238},[242,1197,1198,1200,1203,1205],{"class":244,"line":245},[242,1199,249],{"class":248},[242,1201,1202],{"class":252}," config",[242,1204,256],{"class":248},[242,1206,1207],{"class":259}," {\n",[242,1209,1210,1213,1216],{"class":244,"line":276},[242,1211,1212],{"class":259},"  name: ",[242,1214,1215],{"class":263},"\"widget\"",[242,1217,1218],{"class":259},",\n",[242,1220,1221,1224,1227,1230,1232,1234,1236,1239],{"class":244,"line":295},[242,1222,1223],{"class":282},"  onClick",[242,1225,1226],{"class":259},": () ",[242,1228,1229],{"class":248},"=>",[242,1231,662],{"class":259},[242,1233,301],{"class":282},[242,1235,286],{"class":259},[242,1237,1238],{"class":263},"\"clicked\"",[242,1240,1241],{"class":259},"),\n",[242,1243,1245],{"class":244,"line":1244},4,[242,1246,1247],{"class":259},"};\n",[242,1249,1251,1253],{"class":244,"line":1250},5,[242,1252,868],{"class":282},[242,1254,1255],{"class":259},"(config);\n",[31,1257,1259,1265,1274,1285],{"className":1258},[34],[36,1260,1262,1264],{"className":1261},[39],[41,1263],{"disabled":43,"type":44}," It clones the object and silently drops the function",[36,1266,1268,1270,1271],{"className":1267},[39],[41,1269],{"disabled":43,"type":44}," It clones the object and replaces the function with ",[22,1272,1273],{},"null",[36,1275,1277,333,1279,1281,1282,1284],{"className":1276},[39],[41,1278],{"disabled":43,"type":44},[22,1280,883],{}," (",[22,1283,911],{},")",[36,1286,1288,1290],{"className":1287},[39],[41,1289],{"disabled":43,"type":44}," It clones the function by reference, so both objects share it",[84,1292,1293,1295,1304],{},[87,1294,89],{},[91,1296,1297,1299,1300,1281,1302,1284],{},[94,1298,96],{}," C — It throws a ",[22,1301,883],{},[22,1303,911],{},[91,1305,1306,1308,1309,189,1311,189,1314,189,1316,1318,1319,1322,1323,1325,1326,1329,1330,1332,1333,1335,1336,1339],{},[94,1307,106],{}," The structured clone algorithm has a defined, limited set of cloneable types (primitives, plain objects\u002Farrays, ",[22,1310,802],{},[22,1312,1313],{},"RegExp",[22,1315,805],{},[22,1317,808],{},", typed arrays, ",[22,1320,1321],{},"Blob",", and a few others); functions are explicitly unsupported and cause the call to throw synchronously. This differs from ",[22,1324,391],{},", which silently ",[125,1327,1328],{},"drops"," function properties instead of throwing (making option A the tempting-but-wrong answer, since it describes ",[22,1331,391],{},"'s behavior, not ",[22,1334,868],{},"'s). ",[94,1337,1338],{},"Safety:"," if you need to clone an object that might contain callbacks, strip them out first or use a targeted manual copy instead of a blanket deep-clone utility.",[14,1341,1342,1349,1397,1406,1452],{"language":225},[17,1343,1345,1346,1348],{"id":1344},"q13-a-developer-writes-jsonstringify-on-an-object-with-a-self-reference","Q13. A developer writes ",[22,1347,391],{}," on an object with a self-reference:",[231,1350,1351],{"language":225},[234,1352,1354],{"className":236,"code":1353,"language":225,"meta":238,"style":238},"const node = { value: 1 };\nnode.self = node;\nJSON.stringify(node);\n",[22,1355,1356,1373,1384],{"__ignoreMap":238},[242,1357,1358,1360,1363,1365,1368,1371],{"class":244,"line":245},[242,1359,249],{"class":248},[242,1361,1362],{"class":252}," node",[242,1364,256],{"class":248},[242,1366,1367],{"class":259}," { value: ",[242,1369,1370],{"class":252},"1",[242,1372,273],{"class":259},[242,1374,1375,1378,1381],{"class":244,"line":276},[242,1376,1377],{"class":259},"node.self ",[242,1379,1380],{"class":248},"=",[242,1382,1383],{"class":259}," node;\n",[242,1385,1386,1389,1391,1394],{"class":244,"line":295},[242,1387,1388],{"class":252},"JSON",[242,1390,1119],{"class":259},[242,1392,1393],{"class":282},"stringify",[242,1395,1396],{"class":259},"(node);\n",[91,1398,1399,1400,1402,1403,29],{},"What happens with ",[22,1401,391],{}," versus ",[22,1404,1405],{},"structuredClone(node)",[31,1407,1409,1415,1429,1443],{"className":1408},[34],[36,1410,1412,1414],{"className":1411},[39],[41,1413],{"disabled":43,"type":44}," Both throw an error for circular references",[36,1416,1418,45,1420,1422,1423,1425,1426,1428],{"className":1417},[39],[41,1419],{"disabled":43,"type":44},[22,1421,391],{}," throws a ",[22,1424,336],{}," (\"Converting circular structure to JSON\"); ",[22,1427,868],{}," successfully clones it, preserving the circular reference",[36,1430,1432,45,1434,1436,1437,1439,1440,1442],{"className":1431},[39],[41,1433],{"disabled":43,"type":44},[22,1435,391],{}," succeeds by cloning the circular part as ",[22,1438,1273],{},"; ",[22,1441,868],{}," throws",[36,1444,1446,1448,1449,1451],{"className":1445},[39],[41,1447],{"disabled":43,"type":44}," Both succeed silently, but only ",[22,1450,868],{}," preserves the cycle",[84,1453,1454,1456,1466],{},[87,1455,89],{},[91,1457,1458,97,1460,1422,1462,1425,1464,1428],{},[94,1459,96],{},[22,1461,391],{},[22,1463,336],{},[22,1465,868],{},[91,1467,1468,1470,1471,1473,1474,1477],{},[94,1469,106],{}," JSON has no representation for cycles, so ",[22,1472,391],{}," detects the recursion and throws. The structured clone algorithm, by contrast, is graph-aware — it tracks already-visited objects during the clone and correctly reconstructs the same cyclical shape in the copy, which is exactly the capability referenced in Q7. This is a common trap for anyone who reaches for ",[22,1475,1476],{},"JSON.parse(JSON.stringify(x))"," as a \"deep clone\" one-liner without realizing it fails hard on data shapes like linked lists, trees with parent pointers, or event emitters that reference their own listeners.",[14,1479,1480,1494,1559,1593],{"language":225},[17,1481,1483,1484,1486,1487,569,1489,1491,1492,417],{"id":1482},"q14-a-response-body-has-already-been-consumed-once-via-json-what-happens-on-a-second-call-to-json-or-text-on-the-same-response-object","Q14. A response body has already been consumed once via ",[22,1485,568],{},". What happens on a second call to ",[22,1488,568],{},[22,1490,572],{}," on the same ",[22,1493,518],{},[231,1495,1496],{"language":225},[234,1497,1499],{"className":236,"code":1498,"language":225,"meta":238,"style":238},"const res = await fetch(\"\u002Fapi\u002Fdata\");\nconst data = await res.json();\nconst dataAgain = await res.json();\n",[22,1500,1501,1524,1542],{"__ignoreMap":238},[242,1502,1503,1505,1508,1510,1513,1516,1518,1521],{"class":244,"line":245},[242,1504,249],{"class":248},[242,1506,1507],{"class":252}," res",[242,1509,256],{"class":248},[242,1511,1512],{"class":248}," await",[242,1514,1515],{"class":282}," fetch",[242,1517,286],{"class":259},[242,1519,1520],{"class":263},"\"\u002Fapi\u002Fdata\"",[242,1522,1523],{"class":259},");\n",[242,1525,1526,1528,1531,1533,1535,1537,1539],{"class":244,"line":276},[242,1527,249],{"class":248},[242,1529,1530],{"class":252}," data",[242,1532,256],{"class":248},[242,1534,1512],{"class":248},[242,1536,640],{"class":259},[242,1538,643],{"class":282},[242,1540,1541],{"class":259},"();\n",[242,1543,1544,1546,1549,1551,1553,1555,1557],{"class":244,"line":295},[242,1545,249],{"class":248},[242,1547,1548],{"class":252}," dataAgain",[242,1550,256],{"class":248},[242,1552,1512],{"class":248},[242,1554,640],{"class":259},[242,1556,643],{"class":282},[242,1558,1541],{"class":259},[31,1560,1562,1568,1579,1587],{"className":1561},[34],[36,1563,1565,1567],{"className":1564},[39],[41,1566],{"disabled":43,"type":44}," It returns the same parsed data again, from an internal cache",[36,1569,1571,333,1573,1575,1576,1578],{"className":1570},[39],[41,1572],{"disabled":43,"type":44},[22,1574,336],{}," because the body stream has already been read (a ",[22,1577,518],{}," body can only be consumed once)",[36,1580,1582,1584,1585],{"className":1581},[39],[41,1583],{"disabled":43,"type":44}," It returns ",[22,1586,354],{},[36,1588,1590,1592],{"className":1589},[39],[41,1591],{"disabled":43,"type":44}," It re-fetches the URL automatically",[84,1594,1595,1597,1605],{},[87,1596,89],{},[91,1598,1599,942,1601,1575,1603,1578],{},[94,1600,96],{},[22,1602,336],{},[22,1604,518],{},[91,1606,1607,511,1609,1611,1612,189,1614,189,1616,189,1619,189,1622,1625,1626,1628,1629,45,1632,1635,1636,1638],{},[94,1608,106],{},[22,1610,518],{},"'s body is a one-shot readable stream; once a body-reading method (",[22,1613,568],{},[22,1615,572],{},[22,1617,1618],{},".blob()",[22,1620,1621],{},".arrayBuffer()",[22,1623,1624],{},".formData()",") has consumed it, the stream is marked \"disturbed\" and any further read attempt throws. ",[94,1627,765],{}," if you need the body in multiple forms or multiple places, call ",[22,1630,1631],{},"res.clone()",[125,1633,1634],{},"before"," the first read to get an independent ",[22,1637,518],{}," with its own body stream. Option A is the tempting assumption since many other JS APIs are idempotent on repeated calls, but streams are explicitly not.",[14,1640,1641,1645,1678],{},[17,1642,1644],{"id":1643},"q15-for-storing-a-short-lived-ui-preference-like-sidebar-collapsed-true-that-only-matters-for-the-current-browsing-session-which-storage-mechanism-is-most-idiomatic","Q15. For storing a short-lived UI preference like \"sidebar collapsed = true\" that only matters for the current browsing session, which storage mechanism is most idiomatic?",[31,1646,1648,1656,1662,1670],{"className":1647},[34],[36,1649,1651,45,1653,1655],{"className":1650},[39],[41,1652],{"disabled":43,"type":44},[22,1654,24],{},", so it survives forever",[36,1657,1659,1661],{"className":1658},[39],[41,1660],{"disabled":43,"type":44}," A cookie, so the server can also see it",[36,1663,1665,45,1667,1669],{"className":1664},[39],[41,1666],{"disabled":43,"type":44},[22,1668,28],{},", since the preference is only meaningful for the current tab session",[36,1671,1673,45,1675,1677],{"className":1672},[39],[41,1674],{"disabled":43,"type":44},[22,1676,1042],{},", for its transactional guarantees",[84,1679,1680,1682,1689],{},[87,1681,89],{},[91,1683,1684,1686,1687,1669],{},[94,1685,96],{}," C — ",[22,1688,28],{},[91,1690,1691,45,1693,1695,1696,1698,1699,1701,1702,1704],{},[94,1692,106],{},[94,1694,387],{}," match the storage lifetime to the data's actual lifetime — a value that should reset when the tab closes belongs in ",[22,1697,28],{},", not ",[22,1700,24],{}," (which would leak stale state into unrelated future sessions) or a cookie (which adds unnecessary request overhead for something the server never needs to know). ",[22,1703,1042],{}," is overkill for a single boolean flag; it's meant for structured, queryable, potentially large datasets, not simple key-value preferences.",[14,1706,1707,1720,1756],{},[17,1708,1710,1711,189,1713,189,1715,1717,1718,29],{"id":1709},"q16-for-storing-a-sensitive-authentication-token-why-do-security-conscious-teams-generally-prefer-an-httponly-secure-samesite-cookie-over-localstorage","Q16. For storing a sensitive authentication token, why do security-conscious teams generally prefer an ",[22,1712,213],{},[22,1714,199],{},[22,1716,195],{}," cookie over ",[22,1719,24],{},[31,1721,1723,1729,1740,1748],{"className":1722},[34],[36,1724,1726,1728],{"className":1725},[39],[41,1727],{"disabled":43,"type":44}," Cookies are encrypted automatically by the browser",[36,1730,1732,45,1734,1736,1737,1739],{"className":1731},[39],[41,1733],{"disabled":43,"type":44},[22,1735,24],{}," is readable by any JavaScript running on the page, so it's fully exposed to XSS attacks; an ",[22,1738,213],{}," cookie is inaccessible to JavaScript entirely",[36,1741,1743,1745,1746],{"className":1742},[39],[41,1744],{"disabled":43,"type":44}," Cookies have unlimited storage capacity, unlike ",[22,1747,24],{},[36,1749,1751,45,1753,1755],{"className":1750},[39],[41,1752],{"disabled":43,"type":44},[22,1754,24],{}," values expire after 24 hours automatically, breaking long sessions",[84,1757,1758,1760,1768],{},[87,1759,89],{},[91,1761,1762,97,1764,1736,1766,1739],{},[94,1763,96],{},[22,1765,24],{},[22,1767,213],{},[91,1769,1770,45,1772,1774,1775,1778,1779,1781,1782,1784,1785,1788,1789,1791,1792,1794],{},[94,1771,106],{},[94,1773,1338],{}," any successful XSS injection on the page can run ",[22,1776,1777],{},"localStorage.getItem(...)"," and exfiltrate a token stored there — there's no isolation between \"your\" code and injected code once script execution happens on the page. An ",[22,1780,213],{}," cookie is deliberately hidden from ",[22,1783,164],{}," and any storage API, so even a successful XSS payload can't read it directly (though it could still be ",[125,1786,1787],{},"used"," via same-origin requests, which is why ",[22,1790,195],{}," matters for CSRF — see Q20). Option A is false: cookies are plain text by default, not encrypted. Option C is false: cookies are far more size-constrained than ",[22,1793,24],{},". Option D is a fabricated default.",[14,1796,1797,1804,1918,1969],{"language":225},[17,1798,1800,1801,1803],{"id":1799},"q17-what-is-the-idiomatic-way-to-handle-a-non-2xx-http-response-with-fetch-given-that-it-doesnt-reject-the-promise","Q17. What is the idiomatic way to handle a non-2xx HTTP response with ",[22,1802,583],{},", given that it doesn't reject the promise?",[231,1805,1806],{"language":225},[234,1807,1809],{"className":236,"code":1808,"language":225,"meta":238,"style":238},"async function getUser(id) {\n  const res = await fetch(`\u002Fapi\u002Fusers\u002F${id}`);\n  if (!res.ok) {\n    throw new Error(`Request failed with status ${res.status}`);\n  }\n  return res.json();\n}\n",[22,1810,1811,1830,1855,1868,1895,1900,1912],{"__ignoreMap":238},[242,1812,1813,1816,1819,1822,1824,1827],{"class":244,"line":245},[242,1814,1815],{"class":248},"async",[242,1817,1818],{"class":248}," function",[242,1820,1821],{"class":282}," getUser",[242,1823,286],{"class":259},[242,1825,1826],{"class":633},"id",[242,1828,1829],{"class":259},") {\n",[242,1831,1832,1835,1837,1839,1841,1843,1845,1848,1850,1853],{"class":244,"line":276},[242,1833,1834],{"class":248},"  const",[242,1836,1507],{"class":252},[242,1838,256],{"class":248},[242,1840,1512],{"class":248},[242,1842,1515],{"class":282},[242,1844,286],{"class":259},[242,1846,1847],{"class":263},"`\u002Fapi\u002Fusers\u002F${",[242,1849,1826],{"class":259},[242,1851,1852],{"class":263},"}`",[242,1854,1523],{"class":259},[242,1856,1857,1860,1862,1865],{"class":244,"line":295},[242,1858,1859],{"class":248},"  if",[242,1861,1281],{"class":259},[242,1863,1864],{"class":248},"!",[242,1866,1867],{"class":259},"res.ok) {\n",[242,1869,1870,1873,1876,1879,1881,1884,1886,1888,1891,1893],{"class":244,"line":1244},[242,1871,1872],{"class":248},"    throw",[242,1874,1875],{"class":248}," new",[242,1877,1878],{"class":282}," Error",[242,1880,286],{"class":259},[242,1882,1883],{"class":263},"`Request failed with status ${",[242,1885,634],{"class":259},[242,1887,1119],{"class":263},[242,1889,1890],{"class":259},"status",[242,1892,1852],{"class":263},[242,1894,1523],{"class":259},[242,1896,1897],{"class":244,"line":1250},[242,1898,1899],{"class":259},"  }\n",[242,1901,1903,1906,1908,1910],{"class":244,"line":1902},6,[242,1904,1905],{"class":248},"  return",[242,1907,640],{"class":259},[242,1909,643],{"class":282},[242,1911,1541],{"class":259},[242,1913,1915],{"class":244,"line":1914},7,[242,1916,1917],{"class":259},"}\n",[31,1919,1921,1930,1944,1956],{"className":1920},[34],[36,1922,1924,1926,1927,1929],{"className":1923},[39],[41,1925],{"disabled":43,"type":44}," This pattern is unnecessary — ",[22,1928,583],{}," already throws on error statuses",[36,1931,1933,1935,1936,1939,1940,1943],{"className":1932},[39],[41,1934],{"disabled":43,"type":44}," This is the correct idiom: explicitly check ",[22,1937,1938],{},"res.ok"," (or ",[22,1941,1942],{},"res.status",") and throw before attempting to parse the body",[36,1945,1947,45,1949,1951,1952,1955],{"className":1946},[39],[41,1948],{"disabled":43,"type":44},[22,1950,1938],{}," doesn't exist; you must compare ",[22,1953,1954],{},"res.status === 200"," exactly",[36,1957,1959,1961,1962,1965,1966,1968],{"className":1958},[39],[41,1960],{"disabled":43,"type":44}," You should check ",[22,1963,1964],{},"res.statusText"," instead, since ",[22,1967,1938],{}," is deprecated",[84,1970,1971,1973,1982],{},[87,1972,89],{},[91,1974,1975,1977,1978,1939,1980,1943],{},[94,1976,96],{}," B — This is the correct idiom: explicitly check ",[22,1979,1938],{},[22,1981,1942],{},[91,1983,1984,1986,1987,1989,1990,1993,1994,1997,1998,113,2001,2004,2005,2007,2008,2011,2012,2015,2016,2019,2020,2023],{},[94,1985,106],{}," Since ",[22,1988,583],{}," treats any completed HTTP exchange as a resolved promise (per Q6), the standard, idiomatic pattern is to inspect ",[22,1991,1992],{},"response.ok"," (true for status ",[22,1995,1996],{},"200–299",") immediately after awaiting the fetch and manually throw so downstream ",[22,1999,2000],{},".catch",[22,2002,2003],{},"try-catch"," logic can treat it as an error. Skipping this check means error bodies (often HTML error pages or JSON error payloads with a different shape) get parsed as if they were success data. Option C is wrong because ",[22,2006,1938],{}," covers the whole 2xx range, not just exactly ",[22,2009,2010],{},"200"," (e.g., ",[22,2013,2014],{},"201 Created"," and ",[22,2017,2018],{},"204 No Content"," are also ",[22,2021,2022],{},"ok","). Option D fabricates a deprecation that doesn't exist.",[14,2025,2026,2030,2063],{},[17,2027,2029],{"id":2028},"q18-a-page-needs-to-cache-tens-of-thousands-of-structured-records-eg-an-offline-product-catalog-in-the-browser-which-storage-choice-is-most-appropriate-and-why","Q18. A page needs to cache tens of thousands of structured records (e.g., an offline product catalog) in the browser. Which storage choice is most appropriate, and why?",[31,2031,2033,2041,2047,2055],{"className":2032},[34],[36,2034,2036,45,2038,2040],{"className":2035},[39],[41,2037],{"disabled":43,"type":44},[22,2039,24],{},", because it's the simplest key-value API",[36,2042,2044,2046],{"className":2043},[39],[41,2045],{"disabled":43,"type":44}," Cookies, because they persist across sessions",[36,2048,2050,45,2052,2054],{"className":2049},[39],[41,2051],{"disabled":43,"type":44},[22,2053,1042],{},", because it's asynchronous, supports much larger storage quotas, and allows indexed queries over structured data",[36,2056,2058,45,2060,2062],{"className":2057},[39],[41,2059],{"disabled":43,"type":44},[22,2061,28],{},", because it's the fastest storage mechanism available",[84,2064,2065,2067,2073],{},[87,2066,89],{},[91,2068,2069,1686,2071,2054],{},[94,2070,96],{},[22,2072,1042],{},[91,2074,2075,45,2077,45,2079,2081,2082,2084],{},[94,2076,106],{},[94,2078,1038],{},[22,2080,24],{},"'s synchronous API and typically single-digit-megabyte quota make it unsuitable for large or frequently-read datasets — serializing\u002Fdeserializing tens of thousands of records on the main thread on every read would cause visible jank (per Q9). ",[22,2083,1042],{}," is purpose-built for this: it's asynchronous (doesn't block rendering), commonly allows quotas in the hundreds of megabytes or more (subject to browser\u002Fdevice policy), and supports indexes for efficient querying instead of loading everything into memory at once. Cookies (option B) are capped at a few KB total and would blow the size limit almost immediately, plus they'd be sent needlessly with every request.",[14,2086,2087,2098,2191,2230],{"language":225},[17,2088,2090,2091,2093,2094,2097],{"id":2089},"q19-a-search-as-you-type-feature-fires-a-new-fetch-request-on-every-keystroke-why-should-the-code-use-an-abortcontroller-to-cancel-the-previous-in-flight-request-when-a-new-one-starts","Q19. A search-as-you-type feature fires a new ",[22,2092,583],{}," request on every keystroke. Why should the code use an ",[22,2095,2096],{},"AbortController"," to cancel the previous in-flight request when a new one starts?",[231,2099,2100],{"language":225},[234,2101,2103],{"className":236,"code":2102,"language":225,"meta":238,"style":238},"let controller;\nasync function search(query) {\n  controller?.abort();\n  controller = new AbortController();\n  const res = await fetch(`\u002Fapi\u002Fsearch?q=${query}`, { signal: controller.signal });\n  return res.json();\n}\n",[22,2104,2105,2113,2129,2139,2153,2177,2187],{"__ignoreMap":238},[242,2106,2107,2110],{"class":244,"line":245},[242,2108,2109],{"class":248},"let",[242,2111,2112],{"class":259}," controller;\n",[242,2114,2115,2117,2119,2122,2124,2127],{"class":244,"line":276},[242,2116,1815],{"class":248},[242,2118,1818],{"class":248},[242,2120,2121],{"class":282}," search",[242,2123,286],{"class":259},[242,2125,2126],{"class":633},"query",[242,2128,1829],{"class":259},[242,2130,2131,2134,2137],{"class":244,"line":295},[242,2132,2133],{"class":259},"  controller?.",[242,2135,2136],{"class":282},"abort",[242,2138,1541],{"class":259},[242,2140,2141,2144,2146,2148,2151],{"class":244,"line":1244},[242,2142,2143],{"class":259},"  controller ",[242,2145,1380],{"class":248},[242,2147,1875],{"class":248},[242,2149,2150],{"class":282}," AbortController",[242,2152,1541],{"class":259},[242,2154,2155,2157,2159,2161,2163,2165,2167,2170,2172,2174],{"class":244,"line":1250},[242,2156,1834],{"class":248},[242,2158,1507],{"class":252},[242,2160,256],{"class":248},[242,2162,1512],{"class":248},[242,2164,1515],{"class":282},[242,2166,286],{"class":259},[242,2168,2169],{"class":263},"`\u002Fapi\u002Fsearch?q=${",[242,2171,2126],{"class":259},[242,2173,1852],{"class":263},[242,2175,2176],{"class":259},", { signal: controller.signal });\n",[242,2178,2179,2181,2183,2185],{"class":244,"line":1902},[242,2180,1905],{"class":248},[242,2182,640],{"class":259},[242,2184,643],{"class":282},[242,2186,1541],{"class":259},[242,2188,2189],{"class":244,"line":1914},[242,2190,1917],{"class":259},[31,2192,2194,2203,2213,2224],{"className":2193},[34],[36,2195,2197,2199,2200,2202],{"className":2196},[39],[41,2198],{"disabled":43,"type":44}," Without it, ",[22,2201,583],{}," automatically queues requests and only the last one's callback ever runs, so it's purely a style preference",[36,2204,2206,2208,2209,2212],{"className":2205},[39],[41,2207],{"disabled":43,"type":44}," Without it, older slow responses can resolve ",[125,2210,2211],{},"after"," newer, faster ones, overwriting the UI with stale results (a race condition)",[36,2214,2216,45,2218,2220,2221,2223],{"className":2215},[39],[41,2217],{"disabled":43,"type":44},[22,2219,2096],{}," is required by the Fetch spec for every request, or ",[22,2222,583],{}," throws a warning",[36,2225,2227,2229],{"className":2226},[39],[41,2228],{"disabled":43,"type":44}," It prevents the browser from opening more than one TCP connection at a time",[84,2231,2232,2234,2241],{},[87,2233,89],{},[91,2235,2236,2238,2239,2212],{},[94,2237,96],{}," B — Without it, older slow responses can resolve ",[125,2240,2211],{},[91,2242,2243,2245,2246,2248,2249,2252,2253,2255,2256,2259,2260,2263,2264,2267,2268,2270],{},[94,2244,106],{}," Concurrent ",[22,2247,583],{}," calls resolve independently and in whatever order the network happens to deliver them — there's no built-in request cancellation or sequencing, so a request for ",[22,2250,2251],{},"\"ca\""," typed early can easily resolve ",[125,2254,2211],{}," a request for ",[22,2257,2258],{},"\"cat\""," typed later if the network conditions vary, leaving stale results rendered last. Calling ",[22,2261,2262],{},"controller.abort()"," on the previous controller before issuing a new request cancels the outdated one (its promise rejects with an ",[22,2265,2266],{},"AbortError","), preventing it from ever resolving and overwriting fresher data. Option A invents automatic queuing that doesn't exist — every ",[22,2269,583],{}," call runs independently and concurrently.",[14,2272,2273,2281,2308],{},[17,2274,2276,2277,2280],{"id":2275},"q20-setting-a-cookie-with-set-cookie-sessionabc123-samesitestrict-secure-httponly-primarily-helps-mitigate-which-class-of-attack","Q20. Setting a cookie with ",[22,2278,2279],{},"Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly"," primarily helps mitigate which class of attack?",[31,2282,2284,2290,2296,2302],{"className":2283},[34],[36,2285,2287,2289],{"className":2286},[39],[41,2288],{"disabled":43,"type":44}," SQL injection",[36,2291,2293,2295],{"className":2292},[39],[41,2294],{"disabled":43,"type":44}," Cross-Site Request Forgery (CSRF), by preventing the cookie from being sent on cross-site requests",[36,2297,2299,2301],{"className":2298},[39],[41,2300],{"disabled":43,"type":44}," Cross-Site Scripting (XSS) injection into the page's HTML",[36,2303,2305,2307],{"className":2304},[39],[41,2306],{"disabled":43,"type":44}," DNS spoofing",[84,2309,2310,2312,2317],{},[87,2311,89],{},[91,2313,2314,2316],{},[94,2315,96],{}," B — Cross-Site Request Forgery (CSRF), by preventing the cookie from being sent on cross-site requests",[91,2318,2319,45,2321,45,2323,1939,2326,2329,2330,2332,2333,2336,2337,2339,2340,2342],{},[94,2320,106],{},[94,2322,1338],{},[22,2324,2325],{},"SameSite=Strict",[22,2327,2328],{},"Lax",") tells the browser not to attach this cookie to requests initiated from a different site, which directly defeats the classic CSRF pattern of a malicious page silently submitting a form or request to your app while relying on the browser auto-attaching the victim's session cookie. ",[22,2331,213],{}," (from Q16) protects against XSS ",[125,2334,2335],{},"reading"," the cookie via JavaScript, but that's a separate, complementary protection, not what ",[22,2338,195],{}," is for — so option C conflates the two attributes' purposes. ",[22,2341,199],{}," only ensures the cookie is sent solely over HTTPS, unrelated to injection attacks. Neither attribute has anything to do with SQL injection or DNS-layer attacks.",[2344,2345,2346],"style",{},"html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .sCrzJ, html code.shiki .sCrzJ{--shiki-default:#E36209;--shiki-github-dark:#FFAB70}",{"title":238,"searchDepth":276,"depth":276,"links":2348},[2349,2351,2353,2354,2356,2358,2360,2362,2364,2366,2368,2369,2371,2373,2375,2376,2378,2380,2381,2383],{"id":19,"depth":295,"text":2350},"Q1. Which statement correctly distinguishes localStorage from sessionStorage?",{"id":133,"depth":295,"text":2352},"Q2. A team stores a JWT auth token in a cookie versus localStorage. Which behavior is unique to cookies (not localStorage)?",{"id":228,"depth":295,"text":229},{"id":408,"depth":295,"text":2355},"Q4. When does the storage event fire on the window object?",{"id":491,"depth":295,"text":2357},"Q5. What does fetch() return?",{"id":592,"depth":295,"text":2359},"Q6. A developer writes the following and is confused why the catch block never runs for a 404 response:",{"id":775,"depth":295,"text":2361},"Q7. What is the key advantage of structuredClone(obj) over JSON.parse(JSON.stringify(obj)) for deep-copying data?",{"id":889,"depth":295,"text":2363},"Q8. A page stores several megabytes of data over time via repeated localStorage.setItem calls until the origin's quota (commonly ~5–10MB depending on browser) is exceeded. What happens on the call that exceeds it?",{"id":971,"depth":295,"text":2365},"Q9. Why is heavy, repeated use of localStorage inside a hot code path (e.g., on every scroll or mousemove event) considered a performance anti-pattern?",{"id":1048,"depth":295,"text":2367},"Q10. A user opens the same web app in two separate tabs. They interact with Tab A, which writes to sessionStorage. What does Tab B see?",{"id":1124,"depth":295,"text":1125},{"id":1183,"depth":295,"text":2370},"Q12. What happens when you call structuredClone() on an object that contains a function property?",{"id":1344,"depth":295,"text":2372},"Q13. A developer writes JSON.stringify on an object with a self-reference:",{"id":1482,"depth":295,"text":2374},"Q14. A response body has already been consumed once via .json(). What happens on a second call to .json() or .text() on the same Response object?",{"id":1643,"depth":295,"text":1644},{"id":1709,"depth":295,"text":2377},"Q16. For storing a sensitive authentication token, why do security-conscious teams generally prefer an HttpOnly, Secure, SameSite cookie over localStorage?",{"id":1799,"depth":295,"text":2379},"Q17. What is the idiomatic way to handle a non-2xx HTTP response with fetch, given that it doesn't reject the promise?",{"id":2028,"depth":295,"text":2029},{"id":2089,"depth":295,"text":2382},"Q19. A search-as-you-type feature fires a new fetch request on every keystroke. Why should the code use an AbortController to cancel the previous in-flight request when a new one starts?",{"id":2275,"depth":295,"text":2384},"Q20. Setting a cookie with Set-Cookie: session=abc123; SameSite=Strict; Secure; HttpOnly primarily helps mitigate which class of attack?","md",{},"\u002Fjs\u002F21-web-storage-and-apis",{"title":5,"description":238},"js\u002F21-web-storage-and-apis","_QtEE28wmf2NU-DWn4sbFqhiduQVBXeK13a23vyId4o",1787335397336]