[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"search-suggestions":44,"article-navigator-sendbeacon-reliable-analytics":90,"related-navigator-sendbeacon-reliable-analytics":274,"code:js:true:1ligqxd":404,"code:js:true:1jk86be":405,"code:js:true:1vf9equ":406,"code:js:true:1y9cqpy":407,"code:js:true:152o2o1":408,"comments-019ff19b-fbc7-7069-b3ba-28ffd8fbf4d3":409},[4,20,32],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,[45,49,53,57,61,65,69,73,77,81,84,87],{"slug":46,"name":47,"articles":48},"webdev","Webdev",61,{"slug":50,"name":51,"articles":52},"frontend","Frontend",55,{"slug":54,"name":55,"articles":56},"javascript","Javascript",52,{"slug":58,"name":59,"articles":60},"css","Css",23,{"slug":62,"name":63,"articles":64},"typescript","Typescript",10,{"slug":66,"name":67,"articles":68},"performance","Performance",9,{"slug":70,"name":71,"articles":72},"grammar","Grammar",6,{"slug":74,"name":75,"articles":76},"react","React",5,{"slug":78,"name":79,"articles":80},"html","Html",4,{"slug":82,"name":83,"articles":80},"tutorial","Tutorial",{"slug":85,"name":86,"articles":80},"node","Node",{"slug":88,"name":89,"articles":43},"ai","Ai",{"id":91,"slug":92,"title":93,"subtitle":94,"excerpt":95,"coverUrl":96,"locale":13,"readingMinutes":80,"publishedAt":97,"viewCount":98,"likeCount":19,"commentCount":19,"author":99,"vertical":104,"topic":105,"tags":107,"_count":112,"playground":114,"body":116,"bodyMd":257,"seo":258,"translationGroupId":262,"thread":263,"assessments":265,"translations":270,"quiz":272},"019ff19b-fbc7-7069-b3ba-28ffd8fbf4d3","navigator-sendbeacon-reliable-analytics","Your fetch in beforeunload is silently killed. navigator.sendBeacon guarantees delivery.",null,"When the page unloads, the browser may cancel any in-flight fetch or XHR before it completes. navigator.sendBeacon sends a POST the browser commits to delivering, even after the document is gone.","\u002Fmedia\u002Fcovers\u002Fnavigator-sendbeacon-reliable-analytics.png","2026-08-22T06:47:21.180Z",46,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},"JavaScript",[108,109,110,111],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":66,"name":67,"color":94},{"assessments":113},1,{"slug":92,"title":115},"navigator.sendBeacon — interactive playground",{"blocks":117,"version":113},[118,122,126,132,135,138,141,144,148,151,154,157,165,168,172,175,178,181,184,188,191,194,197,200,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249],{"id":119,"html":120,"type":121},"b1","\u003Cp>When a user closes a tab, your analytics flush typically looks like a \u003Ccode>fetch\u003C\u002Fcode> call inside a \u003Ccode>beforeunload\u003C\u002Fcode> handler. It works in testing and silently fails in production. The browser&#39;s unload policy cancels in-flight requests before they complete, and a fetch fired in \u003Ccode>beforeunload\u003C\u002Fcode> races directly against that. \u003Ccode>navigator.sendBeacon\u003C\u002Fcode> was designed for exactly this moment.\u003C\u002Fp>","paragraph",{"id":123,"html":124,"text":124,"type":125,"level":31},"b2","The API","heading",{"id":127,"code":128,"type":129,"language":130,"highlight":131},"b3","navigator.sendBeacon('\u002Fanalytics', JSON.stringify({ event: 'page_exit', duration: 4200 }));","code","js",[],{"id":133,"html":134,"type":121},"b4","\u003Cp>One call, one guarantee: the browser queues the request and delivers it even if the page unloads before the network round-trip completes. The return value is a boolean — \u003Ccode>true\u003C\u002Fcode> if the request was successfully queued, \u003Ccode>false\u003C\u002Fcode> if the browser declined it (typically because the payload exceeds the size limit). You don&#39;t receive a response body; \u003Ccode>sendBeacon\u003C\u002Fcode> is fire-and-forget.\u003C\u002Fp>",{"id":136,"html":137,"type":121},"b5","\u003Cp>It always sends a \u003Ccode>POST\u003C\u002Fcode>. No custom headers — the request goes out with minimal headers by default.\u003C\u002Fp>",{"id":139,"html":140,"text":140,"type":125,"level":31},"b6","Why fetch fails on page unload",{"id":142,"html":143,"type":121},"b7","\u003Cp>The \u003Ccode>beforeunload\u003C\u002Fcode> event fires synchronously when the page is about to be discarded. Async operations started inside it have no delivery guarantee:\u003C\u002Fp>",{"id":145,"code":146,"type":129,"language":130,"highlight":147},"b8","\u002F\u002F Looks correct. In practice, this often never arrives.\nwindow.addEventListener('beforeunload', () => {\n  fetch('\u002Fanalytics', {\n    method: 'POST',\n    body: JSON.stringify({ event: 'page_exit' }),\n  });\n});",[],{"id":149,"html":150,"type":121},"b9","\u003Cp>The fetch starts, but the browser tears down the page context while it is in-flight. Some browsers cancel the request immediately; others may complete it if the connection is already established, but you cannot rely on that. The \u003Ccode>keepalive: true\u003C\u002Fcode> fetch option tells the browser to outlive the page context, but it caps the total keepalive payload at 64 KB across all active requests and has had reliability issues in older Safari. \u003Ccode>sendBeacon\u003C\u002Fcode> has none of these caveats — it was purpose-built for this pattern.\u003C\u002Fp>",{"id":152,"html":153,"text":153,"type":125,"level":31},"b10","What you can send",{"id":155,"html":156,"type":121},"b11","\u003Cp>\u003Ccode>sendBeacon\u003C\u002Fcode> accepts a \u003Ccode>BodyInit\u003C\u002Fcode> payload, the same types \u003Ccode>fetch\u003C\u002Fcode> accepts for \u003Ccode>body\u003C\u002Fcode>:\u003C\u002Fp>",{"id":158,"type":159,"items":160,"ordered":18},"b12","list",[161,162,163,164],"A \u003Ccode>string\u003C\u002Fcode>","A \u003Ccode>Blob\u003C\u002Fcode>","\u003Ccode>FormData\u003C\u002Fcode>","\u003Ccode>URLSearchParams\u003C\u002Fcode>",{"id":166,"html":167,"type":121},"b13","\u003Cp>For JSON payloads, wrap the string in a \u003Ccode>Blob\u003C\u002Fcode> with the correct content type so the request&#39;s \u003Ccode>Content-Type\u003C\u002Fcode> header is set properly:\u003C\u002Fp>",{"id":169,"code":170,"type":129,"language":130,"highlight":171},"b14","function sendAnalytics(payload) {\n  const body = new Blob(\n    [JSON.stringify(payload)],\n    { type: 'application\u002Fjson' }\n  );\n  navigator.sendBeacon('\u002Fanalytics', body);\n}",[],{"id":173,"html":174,"type":121},"b15","\u003Cp>Without the \u003Ccode>Blob\u003C\u002Fcode> wrapper, \u003Ccode>sendBeacon\u003C\u002Fcode> sends the JSON string with a \u003Ccode>text\u002Fplain\u003C\u002Fcode> content type. Your server may parse it regardless — but the explicit content type is more correct and avoids surprises with strict backends.\u003C\u002Fp>",{"id":176,"html":177,"text":177,"type":125,"level":31},"b16","Use visibilitychange, not beforeunload",{"id":179,"html":180,"type":121},"b17","\u003Cp>\u003Ccode>beforeunload\u003C\u002Fcode> has a second problem beyond delivery: on mobile browsers — particularly iOS Safari — it doesn&#39;t fire reliably when the user switches apps, locks their phone, or is backgrounded by the OS. Events collected during a mobile session can disappear without a trace.\u003C\u002Fp>",{"id":182,"html":183,"type":121},"b18","\u003Cp>The correct trigger for flush-on-exit logic is \u003Ccode>visibilitychange\u003C\u002Fcode>:\u003C\u002Fp>",{"id":185,"code":186,"type":129,"language":130,"highlight":187},"b19","const eventQueue = [];\n\nfunction track(event) {\n  eventQueue.push({ ...event, ts: Date.now() });\n}\n\nfunction flush() {\n  if (eventQueue.length === 0) return;\n  const body = new Blob(\n    [JSON.stringify(eventQueue)],\n    { type: 'application\u002Fjson' }\n  );\n  const queued = navigator.sendBeacon('\u002Fanalytics\u002Fbatch', body);\n  if (queued) eventQueue.length = 0;\n}\n\ndocument.addEventListener('visibilitychange', () => {\n  if (document.visibilityState === 'hidden') flush();\n});",[],{"id":189,"html":190,"type":121},"b20","\u003Cp>\u003Ccode>visibilitychange\u003C\u002Fcode> to \u003Ccode>&#39;hidden&#39;\u003C\u002Fcode> fires when the tab loses focus, when the user navigates away, when they switch apps on mobile, and when the browser is backgrounded — which covers every case \u003Ccode>beforeunload\u003C\u002Fcode> misses. Events collected in memory are batched into one \u003Ccode>sendBeacon\u003C\u002Fcode> call instead of one request per event, which is both cheaper and less likely to exceed the size limit.\u003C\u002Fp>",{"id":192,"html":193,"type":121},"b21","\u003Cp>One note: \u003Ccode>visibilitychange\u003C\u002Fcode> to \u003Ccode>&#39;hidden&#39;\u003C\u002Fcode> does not mean the page is gone. The user may tab back in. If your flush logic clears the queue on a successful \u003Ccode>sendBeacon\u003C\u002Fcode>, you will start a new batch cleanly on the next interaction. That is the right behavior.\u003C\u002Fp>",{"id":195,"html":196,"text":196,"type":125,"level":31},"b22","Browser support",{"id":198,"html":199,"type":121},"b23","\u003Cp>\u003Ccode>sendBeacon\u003C\u002Fcode> is \u003Cstrong>Baseline 2022\u003C\u002Fstrong>: Chrome 39 (2014), Firefox 31 (2014), Safari 11.1 (2018). It has been universally available for years. The feature detection is simple if you need it:\u003C\u002Fp>",{"id":201,"code":202,"type":129,"language":130,"highlight":203},"b24","if (navigator.sendBeacon) {\n  navigator.sendBeacon(url, body);\n} else {\n  fetch(url, { method: 'POST', body, keepalive: true });\n}",[],{"id":205,"html":206,"type":121},"b25","\u003Cp>In practice, if you are targeting any currently-supported browser, the \u003Ccode>else\u003C\u002Fcode> branch never runs.\u003C\u002Fp>",{"id":208,"html":209,"type":121},"b26","\u003C!-- playground:start -->",{"id":211,"html":212,"text":212,"type":125,"level":31},"b27","🎮 Try it yourself",{"id":214,"html":215,"type":121},"b28","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnavigator-sendbeacon-reliable-analytics\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":217,"html":218,"type":121},"b29","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":220,"html":221,"type":121},"b30","\u003C!-- playground:end -->",{"id":223,"html":224,"type":121},"b31","\u003C!-- quiz:start -->",{"id":226,"html":227,"text":227,"type":125,"level":31},"b32","🧠 Test yourself",{"id":229,"html":230,"type":121},"b33","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnavigator-sendbeacon-reliable-analytics\u002Fquiz\">Take the 9-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":232,"html":233,"type":121},"b34","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":235,"html":236,"type":121},"b35","\u003C!-- quiz:end -->",{"id":238,"html":239,"text":239,"type":125,"level":31},"b36","The takeaway",{"id":241,"html":242,"type":121},"b37","\u003Cp>Search your codebase for \u003Ccode>fetch\u003C\u002Fcode> or \u003Ccode>XMLHttpRequest\u003C\u002Fcode> calls inside \u003Ccode>beforeunload\u003C\u002Fcode> or \u003Ccode>unload\u003C\u002Fcode> handlers. They may complete reliably in a Chrome dev session and silently drop data in production — especially on mobile. Replace them with \u003Ccode>navigator.sendBeacon\u003C\u002Fcode>, send JSON as a \u003Ccode>Blob\u003C\u002Fcode> with \u003Ccode>application\u002Fjson\u003C\u002Fcode> to preserve the content type, and trigger the flush from \u003Ccode>visibilitychange\u003C\u002Fcode> rather than \u003Ccode>beforeunload\u003C\u002Fcode> to cover mobile users. You will stop losing events you have been quietly counting on.\u003C\u002Fp>",{"id":244,"type":245},"b38","divider",{"id":247,"html":248,"type":121},"b39","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":250,"type":159,"items":251,"ordered":18},"b40",[252,253,254,255,256],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","💼 \u003Cstrong>LinkedIn\u003C\u002Fstrong> — \u003Ca href=\"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F\">linkedin.com\u002Fin\u002Fparsa-jiravand\u003C\u002Fa>","✉️ \u003Cstrong>Email\u003C\u002Fstrong> (work &amp; contract inquiries): \u003Ca href=\"mailto:bestpractice2026@gmail.com\">bestpractice2026@gmail.com\u003C\u002Fa>","When a user closes a tab, your analytics flush typically looks like a `fetch` call inside a `beforeunload` handler. It works in testing and silently fails in production. The browser's unload policy cancels in-flight requests before they complete, and a fetch fired in `beforeunload` races directly against that. `navigator.sendBeacon` was designed for exactly this moment.\n\n## The API\n\n```js\nnavigator.sendBeacon('\u002Fanalytics', JSON.stringify({ event: 'page_exit', duration: 4200 }));\n```\n\nOne call, one guarantee: the browser queues the request and delivers it even if the page unloads before the network round-trip completes. The return value is a boolean — `true` if the request was successfully queued, `false` if the browser declined it (typically because the payload exceeds the size limit). You don't receive a response body; `sendBeacon` is fire-and-forget.\n\nIt always sends a `POST`. No custom headers — the request goes out with minimal headers by default.\n\n## Why fetch fails on page unload\n\nThe `beforeunload` event fires synchronously when the page is about to be discarded. Async operations started inside it have no delivery guarantee:\n\n```js\n\u002F\u002F Looks correct. In practice, this often never arrives.\nwindow.addEventListener('beforeunload', () => {\n  fetch('\u002Fanalytics', {\n    method: 'POST',\n    body: JSON.stringify({ event: 'page_exit' }),\n  });\n});\n```\n\nThe fetch starts, but the browser tears down the page context while it is in-flight. Some browsers cancel the request immediately; others may complete it if the connection is already established, but you cannot rely on that. The `keepalive: true` fetch option tells the browser to outlive the page context, but it caps the total keepalive payload at 64 KB across all active requests and has had reliability issues in older Safari. `sendBeacon` has none of these caveats — it was purpose-built for this pattern.\n\n## What you can send\n\n`sendBeacon` accepts a `BodyInit` payload, the same types `fetch` accepts for `body`:\n\n- A `string`\n- A `Blob`\n- `FormData`\n- `URLSearchParams`\n\nFor JSON payloads, wrap the string in a `Blob` with the correct content type so the request's `Content-Type` header is set properly:\n\n```js\nfunction sendAnalytics(payload) {\n  const body = new Blob(\n    [JSON.stringify(payload)],\n    { type: 'application\u002Fjson' }\n  );\n  navigator.sendBeacon('\u002Fanalytics', body);\n}\n```\n\nWithout the `Blob` wrapper, `sendBeacon` sends the JSON string with a `text\u002Fplain` content type. Your server may parse it regardless — but the explicit content type is more correct and avoids surprises with strict backends.\n\n## Use visibilitychange, not beforeunload\n\n`beforeunload` has a second problem beyond delivery: on mobile browsers — particularly iOS Safari — it doesn't fire reliably when the user switches apps, locks their phone, or is backgrounded by the OS. Events collected during a mobile session can disappear without a trace.\n\nThe correct trigger for flush-on-exit logic is `visibilitychange`:\n\n```js\nconst eventQueue = [];\n\nfunction track(event) {\n  eventQueue.push({ ...event, ts: Date.now() });\n}\n\nfunction flush() {\n  if (eventQueue.length === 0) return;\n  const body = new Blob(\n    [JSON.stringify(eventQueue)],\n    { type: 'application\u002Fjson' }\n  );\n  const queued = navigator.sendBeacon('\u002Fanalytics\u002Fbatch', body);\n  if (queued) eventQueue.length = 0;\n}\n\ndocument.addEventListener('visibilitychange', () => {\n  if (document.visibilityState === 'hidden') flush();\n});\n```\n\n`visibilitychange` to `'hidden'` fires when the tab loses focus, when the user navigates away, when they switch apps on mobile, and when the browser is backgrounded — which covers every case `beforeunload` misses. Events collected in memory are batched into one `sendBeacon` call instead of one request per event, which is both cheaper and less likely to exceed the size limit.\n\nOne note: `visibilitychange` to `'hidden'` does not mean the page is gone. The user may tab back in. If your flush logic clears the queue on a successful `sendBeacon`, you will start a new batch cleanly on the next interaction. That is the right behavior.\n\n## Browser support\n\n`sendBeacon` is **Baseline 2022**: Chrome 39 (2014), Firefox 31 (2014), Safari 11.1 (2018). It has been universally available for years. The feature detection is simple if you need it:\n\n```js\nif (navigator.sendBeacon) {\n  navigator.sendBeacon(url, body);\n} else {\n  fetch(url, { method: 'POST', body, keepalive: true });\n}\n```\n\nIn practice, if you are targeting any currently-supported browser, the `else` branch never runs.\n\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnavigator-sendbeacon-reliable-analytics\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 9-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnavigator-sendbeacon-reliable-analytics\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n## The takeaway\n\nSearch your codebase for `fetch` or `XMLHttpRequest` calls inside `beforeunload` or `unload` handlers. They may complete reliably in a Chrome dev session and silently drop data in production — especially on mobile. Replace them with `navigator.sendBeacon`, send JSON as a `Blob` with `application\u002Fjson` to preserve the content type, and trigger the flush from `visibilitychange` rather than `beforeunload` to cover mobile users. You will stop losing events you have been quietly counting on.\n\n---\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)\n- 💼 **LinkedIn** — [linkedin.com\u002Fin\u002Fparsa-jiravand](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F)\n- ✉️ **Email** (work & contract inquiries): [bestpractice2026@gmail.com](mailto:bestpractice2026@gmail.com)",{"title":259,"canonical":260,"description":261},"Your fetch in beforeunload is silently killed. navigator.sendBeacon gu","https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fnavigator-sendbeacon-reliable-analytics","When the page unloads, the browser may cancel any in-flight fetch or XHR before it completes. navigator.sendBeacon sends a POST the browser commits to delivering, even after the do","019ff19b-fbc7-7069-b3ba-2fb512ce3d10",{"id":264,"locked":18},"019ff19b-fbfd-769a-bc73-b3a776d0855c",[266],{"id":267,"slug":92,"title":268,"_count":269},"019ff19b-fc34-77eb-b95e-b15a6c5d2ba5","navigator.sendBeacon — reliable analytics on page unload",{"questions":68},[271],{"locale":13,"slug":92},{"id":267,"slug":92,"title":268,"_count":273,"questionCount":68},{"questions":68},{"items":275,"meta":401},[276,288,308,327,347,365,383],{"id":91,"slug":92,"title":93,"subtitle":94,"excerpt":95,"coverUrl":96,"locale":13,"readingMinutes":80,"publishedAt":97,"viewCount":277,"likeCount":19,"commentCount":19,"author":278,"vertical":279,"topic":280,"tags":281,"_count":286,"playground":287,"hasQuiz":17,"hasPlayground":17},47,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},[282,283,284,285],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":66,"name":67,"color":94},{"assessments":113},{"slug":92},{"id":289,"slug":290,"title":291,"subtitle":94,"excerpt":292,"coverUrl":293,"locale":13,"readingMinutes":72,"publishedAt":294,"viewCount":295,"likeCount":19,"commentCount":19,"author":296,"vertical":297,"topic":298,"tags":299,"_count":306,"playground":307,"hasQuiz":17,"hasPlayground":17},"01a00952-9d58-7601-89ac-42fc7bf00fc9","urlpattern-native-route-matching","Stop Writing Regex to Match URLs — The Browser Already Can","A service worker's route regex was missing one anchor and started caching live edit forms as if they were read-only pages. URLPattern, native since 2021, doesn't let you make that mistake.","\u002Fmedia\u002Fcovers\u002Furlpattern-native-route-matching.png","2026-08-20T06:53:07.359Z",150,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},[300,301,302,305],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":303,"name":304,"color":94},"browser","Browser",{"slug":50,"name":51,"color":94},{"assessments":113},{"slug":290},{"id":309,"slug":310,"title":311,"subtitle":94,"excerpt":312,"coverUrl":313,"locale":13,"readingMinutes":80,"publishedAt":314,"viewCount":315,"likeCount":19,"commentCount":19,"author":316,"vertical":317,"topic":318,"tags":320,"_count":325,"playground":326,"hasQuiz":17,"hasPlayground":17},"019ffa10-eeed-707d-9b50-7d83664c7a9a","css-trigonometric-functions-radial-layout","Stop Writing Math.cos() in a Resize Listener","CSS learned trigonometry. Here's the radial menu that used to need a resize listener — and doesn't anymore.","\u002Fmedia\u002Fcovers\u002Fcss-trigonometric-functions-radial-layout.png","2026-08-17T07:03:57.776Z",374,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":58,"name":319},"CSS",[321,322,323,324],{"slug":58,"name":59,"color":94},{"slug":46,"name":47,"color":94},{"slug":54,"name":55,"color":94},{"slug":50,"name":51,"color":94},{"assessments":113},{"slug":310},{"id":328,"slug":329,"title":330,"subtitle":94,"excerpt":331,"coverUrl":332,"locale":13,"readingMinutes":76,"publishedAt":333,"viewCount":334,"likeCount":19,"commentCount":19,"author":335,"vertical":336,"topic":337,"tags":338,"_count":345,"playground":346,"hasQuiz":17,"hasPlayground":17},"019ff19b-f9ca-772e-8f09-cd3d3c640d2b","web-locks-api-tab-coordination","Five tabs open, one refresh token — the race nobody noticed","Users with multiple tabs open triggered a silent race: every tab refreshed the same expiring auth token at once, and the server started invalidating its own sessions. navigator.locks fixes it with a real mutex, no polling or localStorage hacks required.","\u002Fmedia\u002Fcovers\u002Fweb-locks-api-tab-coordination.png","2026-08-15T06:44:54.917Z",525,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},[339,340,341,342],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":343,"name":344,"color":94},"async","Async",{"assessments":113},{"slug":329},{"id":348,"slug":349,"title":350,"subtitle":94,"excerpt":351,"coverUrl":352,"locale":13,"readingMinutes":43,"publishedAt":353,"viewCount":354,"likeCount":19,"commentCount":19,"author":355,"vertical":356,"topic":357,"tags":358,"_count":363,"playground":364,"hasQuiz":17,"hasPlayground":17},"019fe660-8bc3-7444-8c96-86953902f5e0","findlast-search-from-end","You copy and reverse the array to find the last match. `findLast()` searches from the end directly.","The usual workaround — `[...arr].reverse().find()` — allocates a full copy just to walk it backward. ES2023 added `findLast()` and `findLastIndex()` to search from the end without touching the original.","\u002Fmedia\u002Fcovers\u002Ffindlast-search-from-end.png","2026-08-14T07:38:34.486Z",362,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},[359,360,361,362],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":62,"name":63,"color":94},{"assessments":113},{"slug":349},{"id":366,"slug":367,"title":368,"subtitle":94,"excerpt":369,"coverUrl":370,"locale":13,"readingMinutes":80,"publishedAt":371,"viewCount":372,"likeCount":19,"commentCount":19,"author":373,"vertical":374,"topic":375,"tags":376,"_count":381,"playground":382,"hasQuiz":17,"hasPlayground":17},"019fe661-0450-720a-ad6e-5eb995429cd7","sendbeacon-reliable-unload-data","Your `fetch()` in `beforeunload` is being silently dropped. Use `navigator.sendBeacon()`.","Browsers cancel in-flight network requests when a page unloads. The common fix — synchronous XHR — is deprecated. `navigator.sendBeacon()` is the correct, fire-and-forget API designed exactly for this case.","\u002Fmedia\u002Fcovers\u002Fsendbeacon-reliable-unload-data.png","2026-08-13T07:40:48.196Z",399,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":54,"name":106},[377,378,379,380],{"slug":54,"name":55,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":66,"name":67,"color":94},{"assessments":113},{"slug":367},{"id":384,"slug":385,"title":386,"subtitle":94,"excerpt":387,"coverUrl":388,"locale":13,"readingMinutes":80,"publishedAt":389,"viewCount":390,"likeCount":19,"commentCount":19,"author":391,"vertical":392,"topic":393,"tags":394,"_count":399,"playground":400,"hasQuiz":17,"hasPlayground":17},"019ff19b-f763-70e0-abdf-eded59c8e69a","overscroll-behavior-scroll-containment","You're blocking touchmove events to contain scroll. `overscroll-behavior` does it natively.","When a scrollable container hits its edge, the page behind it starts scrolling too. Developers block this with JavaScript event handlers or body overflow tricks. overscroll-behavior is the CSS property that turns off scroll chaining in one line.","\u002Fmedia\u002Fcovers\u002Foverscroll-behavior-scroll-containment.png","2026-08-12T07:38:53.786Z",400,{"id":100,"name":101,"username":102,"avatarUrl":94,"headline":103},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":58,"name":319},[395,396,397,398],{"slug":58,"name":59,"color":94},{"slug":46,"name":47,"color":94},{"slug":50,"name":51,"color":94},{"slug":54,"name":55,"color":94},{"assessments":113},{"slug":385},{"page":113,"perPage":402,"total":56,"totalPages":403},7,8,"\u003Cdiv class=\"shj shj-lang-js shj-oneline\" data-lang=\"js\">navigator\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">sendBeacon\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fanalytics'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-num\">JSON\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">stringify\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> event\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'page_exit'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> duration\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-num\">4200\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-cmnt\">\u002F\u002F Looks correct. In practice, this often never arrives.\n\u003C\u002Fspan>window\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'beforeunload'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-func\">fetch\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fanalytics'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n    method\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'POST'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n    body\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-num\">JSON\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">stringify\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> event\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'page_exit'\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n  \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan> \u003Cspan class=\"shj-func\">sendAnalytics\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>payload\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> body \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">new\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Blob\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\n    \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-num\">JSON\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">stringify\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>payload\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n    \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> type\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'application\u002Fjson'\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n  \u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  navigator\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">sendBeacon\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fanalytics'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> body\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003Cdiv>11\u003C\u002Fdiv>\u003Cdiv>12\u003C\u002Fdiv>\u003Cdiv>13\u003C\u002Fdiv>\u003Cdiv>14\u003C\u002Fdiv>\u003Cdiv>15\u003C\u002Fdiv>\u003Cdiv>16\u003C\u002Fdiv>\u003Cdiv>17\u003C\u002Fdiv>\u003Cdiv>18\u003C\u002Fdiv>\u003Cdiv>19\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> eventQueue \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>;\n\n\u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan> \u003Cspan class=\"shj-func\">track\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>event\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  eventQueue\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">push\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-oper\">...\u003C\u002Fspan>event\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> ts\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Date\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">now\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">function\u003C\u002Fspan> \u003Cspan class=\"shj-func\">flush\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>eventQueue\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>length \u003Cspan class=\"shj-oper\">===\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">return\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> body \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">new\u003C\u002Fspan> \u003Cspan class=\"shj-class\">Blob\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\n    \u003Cspan class=\"shj-bracket\">[\u003C\u002Fspan>\u003Cspan class=\"shj-num\">JSON\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">stringify\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>eventQueue\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">]\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan>\n    \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> type\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'application\u002Fjson'\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n  \u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">const\u003C\u002Fspan> queued \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> navigator\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">sendBeacon\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'\u002Fanalytics\u002Fbatch'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> body\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n  \u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>queued\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> eventQueue\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>length \u003Cspan class=\"shj-oper\">=\u003C\u002Fspan> \u003Cspan class=\"shj-num\">0\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\ndocument\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">addEventListener\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-str\">'visibilitychange'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">=&gt;\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>document\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>visibilityState \u003Cspan class=\"shj-oper\">===\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'hidden'\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-func\">flush\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-js shj-multiline\" data-lang=\"js\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-kwd\">if\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>navigator\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>sendBeacon\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  navigator\u003Cspan class=\"shj-oper\">.\u003C\u002Fspan>\u003Cspan class=\"shj-func\">sendBeacon\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>url\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> body\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan> \u003Cspan class=\"shj-kwd\">else\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-func\">fetch\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>url\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> method\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-str\">'POST'\u003C\u002Fspan>\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> body\u003Cspan class=\"shj-oper\">,\u003C\u002Fspan> keepalive\u003Cspan class=\"shj-oper\">:\u003C\u002Fspan> \u003Cspan class=\"shj-bool\">true\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>",{"locked":18,"total":19,"comments":410},[]]