<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: TrackJS</title>
    <description>The latest articles on DEV Community by TrackJS (@trackjs).</description>
    <link>https://dev.to/trackjs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1130%2Fab572a76-e7f6-4981-9a35-c02302789b8f.png</url>
      <title>DEV Community: TrackJS</title>
      <link>https://dev.to/trackjs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/trackjs"/>
    <language>en</language>
    <item>
      <title>Script Loading Race Conditions</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Wed, 22 Oct 2025 19:32:25 +0000</pubDate>
      <link>https://dev.to/trackjs/script-loading-race-conditions-4cnp</link>
      <guid>https://dev.to/trackjs/script-loading-race-conditions-4cnp</guid>
      <description>&lt;p&gt;You've tested everything locally. Your staging environment is flawless. Then you deploy to production and suddenly users are reporting "undefined is not a function" errors.&lt;/p&gt;

&lt;p&gt;These intermittent failures often come down to script loading race conditions, timing issues that only surface under real, world network conditions. Let's dive into how browsers actually load and execute JavaScript, and why your code might be running before its dependencies are ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Classic Case: jQuery's $ is not defined
&lt;/h2&gt;

&lt;p&gt;One of the most common manifestations of script loading race conditions is the infamous &lt;code&gt;$ is not defined&lt;/code&gt; error. While working with the team at &lt;a href="https://trackjs.com/javascript-errors/jquery-is-not-defined/" rel="noopener noreferrer"&gt;TrackJS on documenting JavaScript errors&lt;/a&gt;, we found this error affects thousands of production applications daily, particularly those loading libraries from CDNs.&lt;/p&gt;

&lt;p&gt;Here's what typically happens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.example.com/jquery.min.js"&lt;/span&gt; &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// This might run BEFORE jQuery loads!&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ready!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though the scripts appear in order, there's no guarantee the first script will finish loading before the second executes. This is especially true when the first script comes from an external domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Browsers Actually Load Scripts
&lt;/h2&gt;

&lt;p&gt;Understanding the browser's script loading pipeline is crucial to preventing these race conditions. Here's what really happens when the browser encounters a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Default (Blocking) Behavior
&lt;/h3&gt;

&lt;p&gt;Without any attributes, scripts block HTML parsing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Parser encounters &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;&lt;/strong&gt; → Pauses HTML parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fetches the script&lt;/strong&gt; → Network request (could be slow!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Executes immediately&lt;/strong&gt; → Runs in order encountered&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resumes HTML parsing&lt;/strong&gt; → Continues building the DOM&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This seems safe, but it's terrible for performance. Modern developers often try to optimize this with async or defer attributes, which is where race conditions creep in.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Async Attribute: Chaos Mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"library.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;async&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scripts download in parallel with HTML parsing&lt;/li&gt;
&lt;li&gt;Execute immediately when downloaded&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No execution order guarantee&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Could run before, during, or after DOMContentLoaded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means &lt;code&gt;app.js&lt;/code&gt; might execute before &lt;code&gt;library.js&lt;/code&gt;, even if &lt;code&gt;library.js&lt;/code&gt; appears first in the HTML. Chaos!&lt;/p&gt;

&lt;h3&gt;
  
  
  The Defer Attribute: Ordered but Delayed
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"library.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;defer&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scripts download in parallel with HTML parsing&lt;/li&gt;
&lt;li&gt;Wait to execute until HTML parsing completes&lt;/li&gt;
&lt;li&gt;Execute in order they appear in the document&lt;/li&gt;
&lt;li&gt;Always run before DOMContentLoaded event&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sounds perfect, but there's a catch: defer only works for external scripts with a &lt;code&gt;src&lt;/code&gt; attribute. Inline scripts ignore defer completely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Race Condition Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: Mixed Loading Strategies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"jquery.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="c1"&gt;// This inline script runs IMMEDIATELY, before deferred jQuery!&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Broken!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The inline script executes immediately while jQuery waits due to defer. Result: &lt;code&gt;$ is not defined&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: Dynamic Script Injection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Dynamically injected scripts are async by default&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dependency.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// This runs immediately, not waiting for dependency.js&lt;/span&gt;
&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Error if this needs dependency.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 3: Network Timing Variations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://fast-cdn.com/small-lib.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://slow-cdn.com/huge-lib.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/app.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In development (fast network): Everything loads in order.&lt;br&gt;
In production (variable network): &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User on fast connection: Works fine&lt;/li&gt;
&lt;li&gt;User on 3G: small-lib loads, huge-lib stalls, app.js breaks&lt;/li&gt;
&lt;li&gt;User behind corporate firewall: CDNs blocked entirely&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  How to Prevent Script Loading Race Conditions
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Explicit Load Event Handling
&lt;/h3&gt;

&lt;p&gt;Instead of hoping scripts load in order, explicitly wait for them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loadScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Guaranteed order&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.example.com/jquery.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cdn.example.com/plugins.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;loadScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/js/app.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Everything is loaded!&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Safe to use jQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Script loading failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Handle gracefully&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Module Systems (ES6 Modules)
&lt;/h3&gt;

&lt;p&gt;Modern JavaScript modules handle dependencies explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app.js&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./plugin.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// These imports are guaranteed to resolve before this code runs&lt;/span&gt;
&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;initPlugin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With native ES6 modules or bundlers like Webpack, dependencies are explicit and loading order is guaranteed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Script Loading Libraries
&lt;/h3&gt;

&lt;p&gt;Libraries like LoadJS or HeadJS provide robust script loading with dependency management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;loadjs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jquery.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plugins.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;loadjs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// All core scripts are loaded&lt;/span&gt;
  &lt;span class="nf"&gt;initializeApp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Defensive Coding Patterns
&lt;/h3&gt;

&lt;p&gt;Always check for dependencies before using them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Retry pattern for external dependencies&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;waitForGlobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxAttempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;attempts&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;attempts&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;check&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; failed to load after &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;maxAttempts&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; attempts`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;check&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Usage&lt;/span&gt;
&lt;span class="nf"&gt;waitForGlobal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Safe to use jQuery&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initApp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Bundle Everything
&lt;/h3&gt;

&lt;p&gt;The most reliable solution? Bundle all your JavaScript together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// webpack.config.js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// All dependencies bundled in correct order&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One file, no external dependencies, no race conditions. The tradeoff is bundle size and caching granularity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing for Race Conditions
&lt;/h2&gt;

&lt;p&gt;Race conditions are notorious for working fine in development but breaking in production. Here's how to catch them early:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Throttle Your Network
&lt;/h3&gt;

&lt;p&gt;Chrome DevTools → Network tab → Throttling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test with "Slow 3G" preset&lt;/li&gt;
&lt;li&gt;Create custom profiles matching your users' connections&lt;/li&gt;
&lt;li&gt;Add variable latency to simulate real networks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Block External Resources
&lt;/h3&gt;

&lt;p&gt;Test what happens when CDNs fail:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open DevTools&lt;/li&gt;
&lt;li&gt;Network tab → Block request domain&lt;/li&gt;
&lt;li&gt;Add CDN domains to blocklist&lt;/li&gt;
&lt;li&gt;Reload and observe failures&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  3. Randomize Script Loading
&lt;/h3&gt;

&lt;p&gt;Add artificial delays to expose race conditions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In development only!&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalAppendChild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tagName&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SCRIPT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Random delay between 0-2 seconds&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;originalAppendChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;originalAppendChild&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Use Error Monitoring
&lt;/h3&gt;

&lt;p&gt;Production race conditions often only appear under specific conditions. &lt;a href="https://trackjs.com/" rel="noopener noreferrer"&gt;Use error monitoring&lt;/a&gt; to catch them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Track script loading errors&lt;/li&gt;
&lt;li&gt;Monitor undefined function/variable errors
&lt;/li&gt;
&lt;li&gt;Correlate errors with network conditions&lt;/li&gt;
&lt;li&gt;Identify patterns (specific browsers, connection speeds, regions)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Script execution order is not guaranteed&lt;/strong&gt; unless you explicitly control it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async and defer change loading behavior&lt;/strong&gt; in ways that can introduce race conditions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network conditions in production&lt;/strong&gt; are wildly different from development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN dependencies&lt;/strong&gt; add points of failure you don't control&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defensive coding&lt;/strong&gt; and explicit dependency management prevent most issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test with realistic network conditions&lt;/strong&gt; to catch problems early&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor production errors&lt;/strong&gt; to catch edge cases you didn't anticipate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Script loading race conditions are one of those problems that seem simple but hide tremendous complexity. The key is understanding how browsers actually work, not how we think they work. Once you grasp the loading pipeline, you can write JavaScript that's resilient to the chaos of real-world networks.&lt;/p&gt;

&lt;p&gt;Remember: every external script is a potential race condition. Every inline script is a potential execution order issue. Plan accordingly, and your production JavaScript will be far more reliable.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have you encountered bizarre script loading issues in production? What patterns do you use to prevent race conditions? Share your war stories in the comments!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>debugging</category>
      <category>performance</category>
    </item>
    <item>
      <title>The Hidden Cost of Silent API Failures in Production</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Thu, 16 Oct 2025 15:12:59 +0000</pubDate>
      <link>https://dev.to/trackjs/the-hidden-cost-of-silent-api-failures-in-production-1gg5</link>
      <guid>https://dev.to/trackjs/the-hidden-cost-of-silent-api-failures-in-production-1gg5</guid>
      <description>&lt;p&gt;The checkout flow worked perfectly in staging. All the tests passed. The team celebrated shipping on time. Three weeks later, you're in an emergency meeting explaining how you lost $50,000 in revenue because nobody knew the payment API was returning HTML error pages instead of JSON.&lt;/p&gt;

&lt;p&gt;This is a true story, just with the numbers rounded for their protection.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Perfect Storm Nobody Saw Coming
&lt;/h2&gt;

&lt;p&gt;Here's what happened: Their payment processor's API started having intermittent issues. Nothing major, just occasional 503 errors during high load. The kind of thing that happens to every API eventually.&lt;/p&gt;

&lt;p&gt;But instead of returning a JSON error response, the payment gateway's load balancer served its default HTML maintenance page. The frontend code tried to parse this HTML as JSON, hit an &lt;a href="https://trackjs.com/javascript-errors/unexpected-token/" rel="noopener noreferrer"&gt;Unexpected token '&amp;lt;' error&lt;/a&gt;, and silently swallowed the exception in a poorly-written try-catch block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The code that cost $50,000&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/process-payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 💥 Dies here when HTML returned&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;showSuccessMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;showErrorMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Developer assumed this would only catch network errors&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Network error, will retry...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// But it also caught JSON parsing errors&lt;/span&gt;
  &lt;span class="c1"&gt;// Customer sees nothing, assumes payment worked&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Customers would click "Complete Purchase," see a spinner, then... nothing. No error message. No success message. Many assumed it worked and left. Others tried multiple times, creating duplicate charges when the API recovered. Some gave up and bought from a competitor.&lt;/p&gt;

&lt;p&gt;The worst part? &lt;strong&gt;This ran for three weeks before anyone noticed.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Silent Failures Are Your Biggest Threat
&lt;/h2&gt;

&lt;p&gt;Loud failures are easy. Database down? Customers see a maintenance page. Everyone knows something's wrong.&lt;/p&gt;

&lt;p&gt;Silent failures are insidious. They look like success. But revenue is quietly bleeding out.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Mismatched Content Types
&lt;/h3&gt;

&lt;p&gt;Your code expects JSON, but gets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML error pages from load balancers&lt;/li&gt;
&lt;li&gt;XML from legacy systems&lt;/li&gt;
&lt;li&gt;Plain text from misconfigured endpoints&lt;/li&gt;
&lt;li&gt;HTML login pages from expired auth&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Overly Optimistic Error Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// What junior devs write&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// "It'll be fine"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// What senior devs write after being burned&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;apiCall&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Validate EVERYTHING&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Expected JSON, got &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Log to monitoring service&lt;/span&gt;
  &lt;span class="nx"&gt;errorReporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/endpoint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// User sees actual error&lt;/span&gt;
  &lt;span class="nf"&gt;showUserError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment processing temporarily unavailable&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Re-throw to prevent silent failure&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Missing Observability Layers
&lt;/h3&gt;

&lt;p&gt;Most teams monitor infrastructure metrics but miss application-level failures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Infrastructure says everything is fine&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="nx"&gt;OK&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;145&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;  
&lt;span class="err"&gt;✅&lt;/span&gt; &lt;span class="nx"&gt;Memory&lt;/span&gt; &lt;span class="nx"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;

&lt;span class="c1"&gt;// But the actual response was:&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="nx"&gt;DOCTYPE&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="nx"&gt;Service&lt;/span&gt; &lt;span class="nx"&gt;Unavailable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/title&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nx"&gt;head&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Maintenance&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/body&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/html&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Which caused:&lt;/span&gt;
&lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;parsing&lt;/span&gt; &lt;span class="nx"&gt;failed&lt;/span&gt;
&lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt; &lt;span class="nx"&gt;flow&lt;/span&gt; &lt;span class="nx"&gt;broken&lt;/span&gt;
&lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="nx"&gt;Customer&lt;/span&gt; &lt;span class="nx"&gt;charged&lt;/span&gt; &lt;span class="nx"&gt;but&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="nx"&gt;created&lt;/span&gt;
&lt;span class="err"&gt;❌&lt;/span&gt; &lt;span class="nx"&gt;$50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;000&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;lost&lt;/span&gt; &lt;span class="nx"&gt;revenue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The True Cost of Silent Failures
&lt;/h2&gt;

&lt;p&gt;Let's do the math on that $50,000 loss:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;impactAnalysis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;directLoss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;failedTransactions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;823&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;averageOrderValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;47.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lostRevenue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="nx"&gt;_092&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;indirectLoss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;customerServiceHours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;hourlyCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;laborCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="nx"&gt;_200&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;reputationDamage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;negativeReviews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;estimatedLifetimeValueLost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="nx"&gt;_900&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;technicalDebt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;emergencyFixHours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;developerHourlyCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;rushDeploymentCost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;

  &lt;span class="na"&gt;totalImpact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;58&lt;/span&gt;&lt;span class="nx"&gt;_192&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Actual cost: $&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;totalImpact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// "But our monitoring showed 99.9% uptime!" 🤡&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building a Defense System
&lt;/h2&gt;

&lt;p&gt;You can't prevent all API failures, but you can prevent them from being silent. Here's your defensive playbook:&lt;/p&gt;

&lt;h3&gt;
  
  
  Layer 1: Paranoid Parsing
&lt;/h3&gt;

&lt;p&gt;Never trust external data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;APIClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;safeFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Accept&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Log non-JSON responses BEFORE parsing&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Capture the actual response for debugging&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;logError&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Non-JSON response received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s2"&gt;`API returned &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unknown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; instead of JSON`&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 2: Circuit Breakers with Metrics
&lt;/h3&gt;

&lt;p&gt;Track failure patterns, not just failures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MonitoredCircuitBreaker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;circuitOpen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Circuit breaker &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is open`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recordFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// Track the TYPE of failure&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unexpected token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;htmlResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;recordFailure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Keep only recent failures&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cutoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cutoff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trip&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 3: User-Visible Degradation
&lt;/h3&gt;

&lt;p&gt;When things fail, fail loudly to the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of silent failure&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;SilentCheckout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;processing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCheckout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// Success path&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// User sees nothing! &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;setProcessing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Explicit failure states&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ResilientCheckout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleCheckout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processPayment&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="c1"&gt;// User ALWAYS sees something went wrong&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unexpected token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment service is temporarily unavailable. Please try again in a few minutes.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Track for analytics&lt;/span&gt;
        &lt;span class="nx"&gt;analytics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;track&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payment_api_html_response&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment failed. Please check your information and try again.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="c1"&gt;// Log for developers&lt;/span&gt;
      &lt;span class="nx"&gt;errorReporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;captureException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Alert&lt;/span&gt; &lt;span class="nx"&gt;severity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleCheckout&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Retry&lt;/span&gt; &lt;span class="nx"&gt;Payment&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Alert&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Layer 4: Proactive Monitoring
&lt;/h3&gt;

&lt;p&gt;Don't wait for customers to complain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Synthetic monitoring - run every 5 minutes&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;syntheticCheckoutTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testCard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4111111111111111&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/process-payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;testCard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Validate response format, not just status&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;contentType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;alertOncall&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;critical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment API returning HTML&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;alertOncall&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;severity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;critical&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
      &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Synthetic checkout test failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Morning After Fix
&lt;/h2&gt;

&lt;p&gt;After the $50,000 incident, here's what the team implemented:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mandatory response validation&lt;/strong&gt; - Every API call validates content-type before parsing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error budgets&lt;/strong&gt; - If JSON parsing errors exceed 0.1%, alerts fire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer-facing error messages&lt;/strong&gt; - No more silent failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay capability&lt;/strong&gt; - Failed transactions can be retried when service recovers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time revenue monitoring&lt;/strong&gt; - Sudden drops trigger immediate investigation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most importantly, they learned that &lt;a href="https://trackjs.com/javascript-errors/unexpected-token/" rel="noopener noreferrer"&gt;Unexpected token errors&lt;/a&gt; aren't just annoying console noise - they're canaries in the coal mine warning you about API contract violations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Action Items
&lt;/h2&gt;

&lt;p&gt;Stop reading and go check your production logs right now. Search for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Unexpected token &amp;lt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSON.parse&lt;/code&gt; errors
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SyntaxError&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Empty catch blocks in payment/checkout code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find any, you might be losing money right now.&lt;/p&gt;

&lt;p&gt;Then implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Today:&lt;/strong&gt; Add content-type validation to your API client&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This week:&lt;/strong&gt; Set up monitoring for JSON parsing errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This sprint:&lt;/strong&gt; Add circuit breakers to critical paths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This quarter:&lt;/strong&gt; Run chaos engineering tests with HTML injection&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because the next silent failure might not just cost $50,000. It might cost you a customer who never comes back.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Remember: In production, &lt;a href="https://trackjs.com/" rel="noopener noreferrer"&gt;the scariest errors&lt;/a&gt; aren't the ones that throw exceptions - they're the ones that don't.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>api</category>
      <category>devops</category>
      <category>javascript</category>
    </item>
    <item>
      <title>From StackOverflow to Vibe Coding: The Evolution of Copy-Paste Development</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Wed, 10 Sep 2025 20:30:32 +0000</pubDate>
      <link>https://dev.to/trackjs/from-stackoverflow-to-vibe-coding-the-evolution-of-copy-paste-development-4ngl</link>
      <guid>https://dev.to/trackjs/from-stackoverflow-to-vibe-coding-the-evolution-of-copy-paste-development-4ngl</guid>
      <description>&lt;p&gt;I was helping a developer debug their Vue app last week. The entire thing was written by Claude. Not "assisted by" or "pair-programmed with"—just straight-up written by an AI from a series of prompts.&lt;/p&gt;

&lt;p&gt;The bug? A classic race condition that anyone who's written async JavaScript would spot immediately. But here's the thing—they'd never written async JavaScript. They'd only ever prompted for it.&lt;/p&gt;

&lt;p&gt;And honestly? I'm not even surprised. There's been copy-paste developers since the dawn of programming. They just changed where they copy it from.&lt;/p&gt;

&lt;h2&gt;
  
  
  The StackOverflow Era (2008-2020)
&lt;/h2&gt;

&lt;p&gt;Remember when StackOverflow was the dirty little secret of professional development? We'd have it open in another tab, frantically searching for that one answer with the green checkmark.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// copied from StackOverflow&lt;/span&gt;
&lt;span class="nx"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;xy&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x3&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mh"&gt;0x8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've been copy-pasting this little guy for years.&lt;/p&gt;

&lt;p&gt;At least with StackOverflow, you got to see other developers arguing in the comments about why the solution was wrong. Educational, in a way. You'd learn that your code was bad, but also &lt;em&gt;why&lt;/em&gt; it was bad, usually from someone with strong opinions about semicolons.&lt;/p&gt;

&lt;h2&gt;
  
  
  The GitHub Copilot Transition (2021-2023)
&lt;/h2&gt;

&lt;p&gt;Then came Copilot, and suddenly we were copying code &lt;em&gt;before we even knew we needed it&lt;/em&gt;. It was like having that one senior developer who types faster than they think, except it was trained on every npm package that ever existed, including the ones with critical security vulnerabilities.&lt;/p&gt;

&lt;p&gt;The weird part about Copilot was how it made you feel like you were still writing code. You'd type a comment, hit tab, and boom—instant function. You were "programming" in the same way that heating up a frozen dinner is "cooking."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Function to validate email&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Copilot autocompleted this regex I'll never understand&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(([^&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span class="se"&gt;\[\]\\&lt;/span&gt;&lt;span class="sr"&gt;.,;:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;@"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;(\.[^&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;&amp;gt;()&lt;/span&gt;&lt;span class="se"&gt;\[\]\\&lt;/span&gt;&lt;span class="sr"&gt;.,;:&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;@"&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;".+"&lt;/span&gt;&lt;span class="se"&gt;))&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;((\[[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}\.[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}\.[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}\.[&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]{1,3}\])&lt;/span&gt;&lt;span class="sr"&gt;|&lt;/span&gt;&lt;span class="se"&gt;(([&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;\-&lt;/span&gt;&lt;span class="sr"&gt;0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.)&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;]{2,}))&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We went from copying whole functions to copying whole files. Progress?&lt;/p&gt;

&lt;h2&gt;
  
  
  The ChatGPT Revolution (2023-Present)
&lt;/h2&gt;

&lt;p&gt;Now we don't even pretend to write code. We just describe what we want in plain English and hope for the best. It's called "prompt engineering," which is like calling yourself a "search engineer" because you're good at Google.&lt;/p&gt;

&lt;p&gt;The modern development workflow:&lt;/p&gt;

&lt;p&gt;I watched a junior developer build an entire e-commerce site this way. They couldn't explain what useEffect did, but they could prompt their way through implementing Stripe payments. It's simultaneously impressive and terrifying.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Plot Twist: AI-Generated Bugs Need AI-Powered Debugging
&lt;/h2&gt;

&lt;p&gt;Here's the thing nobody talks about: when AI writes your code, traditional debugging becomes nearly impossible. You can't debug code you don't understand. It's like trying to fix a car when you don't know what an engine is.&lt;/p&gt;

&lt;p&gt;Last month, we saw a production issue where React was throwing hydration mismatch errors. The developer who wrote it (or rather, prompted for it) had no idea what hydration even meant. They just knew that ChatGPT said to use &lt;code&gt;Date.now()&lt;/code&gt; in their component and now production was on fire.&lt;/p&gt;

&lt;p&gt;This is exactly why we built an &lt;a href="https://trackjs.com/blog/ai-code-debugger/" rel="noopener noreferrer"&gt;AI code debugger&lt;/a&gt; at TrackJS. Not because we wanted to—I actually hate that we need this—but because it's the logical conclusion of where we are. If AI is writing the bugs, AI needs to fix them too.&lt;/p&gt;

&lt;p&gt;The debugger sees the full error context: stack traces, browser info, user actions, network requests. It's like having a senior developer who actually understands the code review it, except this senior developer has read every JavaScript error that ever existed and doesn't judge you for not knowing what a Promise is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Truth
&lt;/h2&gt;

&lt;p&gt;We've gone from copying code we don't understand from StackOverflow to copying code we don't understand from AI. The only real difference is the AI doesn't passive-aggressively tell us our question is a duplicate.&lt;/p&gt;

&lt;p&gt;But here's what actually bothers me: we're creating a generation of developers who can build anything but fix nothing. They can prompt their way through creating a complex app but can't debug a simple race condition. They know how to ask for code but not how to read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens Next?
&lt;/h2&gt;

&lt;p&gt;I don't think we're going back. The genie's out of the bottle, and honestly, the productivity gains are too good to give up. I can build prototypes in hours that used to take days.&lt;/p&gt;

&lt;p&gt;The difference is that now the entire stack is becoming opaque. We're building on foundations we don't understand, with code we didn't write, debugging errors we can't comprehend. It's turtles all the way down, except the turtles are language models trained on Reddit comments.&lt;/p&gt;

&lt;p&gt;Maybe that's fine. Maybe understanding your code is overrated. Maybe we're entering an era where software development is more about knowing what to build than how to build it.&lt;/p&gt;

&lt;p&gt;Or maybe we're setting ourselves up for a spectacular failure when all these AI-generated codebases need to be maintained by humans who've never actually written a for loop.&lt;/p&gt;

&lt;p&gt;Either way, at least the debugging tools are keeping up. Our &lt;a href="https://trackjs.com/blog/ai-code-debugger/" rel="noopener noreferrer"&gt;AI code debugger&lt;/a&gt; can explain why your AI-generated code is failing, complete with examples and fixes. It's AI all the way down, and I hate that it works so well.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's your take? Are we evolving or devolving as developers? Have you shipped AI-generated code you don't understand? Drop a comment below—I promise I won't judge. We're all just trying to ship features and go home.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Hard-Won Lessons Building Maintainable Web Applications</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Tue, 06 Oct 2020 14:45:45 +0000</pubDate>
      <link>https://dev.to/trackjs/hard-won-lessons-building-maintainable-web-applications-5cc5</link>
      <guid>https://dev.to/trackjs/hard-won-lessons-building-maintainable-web-applications-5cc5</guid>
      <description>&lt;p&gt;I've built web applications for 15 years. Some have succeeded and flourished, others have crashed and burned. But I've learned some hard-won lessons along the way: techniques that  correlate with maintainable code and long-term success. Maybe they can help you.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Write as little JavaScript as possible.
&lt;/h2&gt;

&lt;p&gt;Only write code that you &lt;em&gt;need&lt;/em&gt;. Many web application patterns can be accomplished with HTML and CSS. You should do it there, if at all possible. No one wants to use your "beautiful modern input control".&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Write boring code.
&lt;/h2&gt;

&lt;p&gt;Writing "as little JavaScript as possible" isn't about optimizing "lines of code". It's about reducing the &lt;em&gt;concepts&lt;/em&gt; in your code. More simple code is 10x better than compact clever code.&lt;/p&gt;

&lt;p&gt;You want your app filled with code that any novice can pick up, understand, and work with. Because any novice could be the next developer responsible for maintaining it.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Use progressive enhancement.
&lt;/h2&gt;

&lt;p&gt;Your app should &lt;em&gt;mostly&lt;/em&gt; work without JavaScript. &lt;em&gt;Really&lt;/em&gt;. Not because anyone browses the web without JavaScript, but because &lt;strong&gt;Scripts fails to load&lt;/strong&gt; (See #5) and &lt;strong&gt;JavaScript often breaks&lt;/strong&gt; (See #6). When it does, give your users a fallback plan with solid HTML that does traditional form posts against your API.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. You can't test every browser. Don't try.
&lt;/h2&gt;

&lt;p&gt;Chrome, Firefox, Safari, Mobile Safari, Internet Explorer, Edge Pre-Blink, Edge Post-Blink, Facebook embedded, WeChat, Gameboy, and that smart microwave from Samsung. There are too many browsers with too many quirks. You can't test them all. If you find yourself with flaky code that's often breaking across browsers, you're probably being too clever. See #2 and #3.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Scripts will fail to load.
&lt;/h2&gt;

&lt;p&gt;The Internet is way less reliable than most developers think. Scripts fail to be loaded all the time. As many as &lt;a href="https://trackjs.com/blog/fast-and-resilient-webapps/" rel="noopener noreferrer"&gt;10% of requests fail on slower mobile connections&lt;/a&gt;. When one of these failed requests is your dependency &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag, how does your application behave?&lt;/p&gt;

&lt;p&gt;Most apps just blow up with an error like &lt;code&gt;jQuery is undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If your app followed "#3 Use progressive enhancement", the user would have never noticed, and your app would feel more reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Monitor everything.
&lt;/h2&gt;

&lt;p&gt;Your code &lt;em&gt;will&lt;/em&gt; break, and you have no idea how. If you did, you would have fixed it already!&lt;/p&gt;

&lt;p&gt;Users will do unpredictable things with unpredictable browsers, and you need to know when it happens. &lt;a href="https://trackjs.com/" rel="noopener noreferrer"&gt;Monitoring your website&lt;/a&gt; from &lt;a href="https://trackjs.com/blog/separate-monitoring/" rel="noopener noreferrer"&gt;separate infrastructure&lt;/a&gt; gives you the feedback to know when you missed something, and fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Keep it simple as long as possible.
&lt;/h2&gt;

&lt;p&gt;Most web applications aren't big. Some of the most important and valuable apps I've ever built are less than 10,000 lines of code. Way less.&lt;/p&gt;

&lt;p&gt;Until you have more than 1000 lines of JavaScript, you don't need bundlers or webpack or frameworks. You need a script tag pointing to a &lt;code&gt;scripts.js&lt;/code&gt; file. You don't even need to minify it.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Use a modern framework.
&lt;/h2&gt;

&lt;p&gt;If you really need to build something big (see #1, #2, #3, and #7), use a modern framework. Don't invent one yourself. It probably won't be quite as good and it's a huge waste of your time.&lt;/p&gt;

&lt;p&gt;But &lt;strong&gt;it doesn't matter which one you pick&lt;/strong&gt;. It really doesn't. Throw a dart and go. You'll likely &lt;a href="https://trackjs.com/blog/fleeting-frontend/" rel="noopener noreferrer"&gt;rebuild the frontend every few years anyway&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Server-side code is better than client-side code.
&lt;/h2&gt;

&lt;p&gt;If you can implement a feature in either the client or the server, &lt;strong&gt;build it on the server&lt;/strong&gt;. The server is more stable(#4), more reliable (#5), &lt;a href="https://trackjs.com/stats/" rel="noopener noreferrer"&gt;less error prone&lt;/a&gt;, and will likely be viable for much longer than the client-side code (#8).&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Performance is important
&lt;/h2&gt;

&lt;p&gt;Just because you have a fast device on a good network doesn't mean your users do. Most users are on older computers, cheaper phones, and more remote networks. If your app isn't fast, it doesn't matter what else it does.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trackjs.com/blog/best-practices-javascript-page-weight/" rel="noopener noreferrer"&gt;Write less JavaScript&lt;/a&gt;. Serve fewer, smaller assets. Do work asynchronously on servers or web workers.&lt;/p&gt;

&lt;p&gt;You'll need to see how &lt;em&gt;your users&lt;/em&gt; experience the performance of your site. You should &lt;a href="https://requestmetrics.com/" rel="noopener noreferrer"&gt;monitor real-user performance&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. The cache will lie to you.
&lt;/h2&gt;

&lt;p&gt;Some browsers will discard their asset caches randomly. Others will hold onto their cache for months with no explanation. You do not control this. &lt;a href="https://trackjs.com/blog/backwards-compatability/" rel="noopener noreferrer"&gt;Build backward-compatible code and handle unexpected requests&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. You don't understand the browser.
&lt;/h2&gt;

&lt;p&gt;Web browsers are incredibly complex and constantly changing. New technologies, UI patterns, draft standards, exception pathways, and extension hooks are being changed all the time with evergreen releases. They will change in subtly different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. Third-parties will change things when you least want them to.
&lt;/h2&gt;

&lt;p&gt;When you rely on a third-party to host your scripts, provide an API, or provide a service, you're giving up control of when changes happen. The decisions of other teams can break your app when you least expect it.&lt;/p&gt;

&lt;p&gt;If at all possible, host assets yourselves. Have practical fallbacks when external services are offline or different than what you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  14. Ad-blockers break everything.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://trackjs.com/blog/avoid-ad-blocker-errors/" rel="noopener noreferrer"&gt;Ad blockers are the worst.&lt;/a&gt; In their effort to fight abusive advertising, they have broken code around the web with overly aggressive rules and domain exclusions. Up to 25% of your users have an ad-blocker, with varying levels of strictness. Do you know how your web app works for them?&lt;/p&gt;

&lt;p&gt;Monitor your app (#6) and use progressive enhancement (#3).&lt;/p&gt;

&lt;h2&gt;
  
  
  15. You don't need to understand everything.
&lt;/h2&gt;

&lt;p&gt;The web development ecosystem is huge, diverse, and changing. You don't need to understand everything, and no one does. Find tools that work for you and get on with development. It doesn't matter what anyone else is doing.&lt;/p&gt;




&lt;p&gt;I could have saved myself a lot of pain and a lot of long-nights if I had understood these thing earlier in my career. But I guess that's just getting older and wiser 😀.&lt;/p&gt;

&lt;p&gt;What would you add to this list? &lt;a href="https://twitter.com/toddhgardner/status/1225552111221530626" rel="noopener noreferrer"&gt;Let me know on Twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>codenewbie</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building Request Metrics</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Mon, 23 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/building-request-metrics-5437</link>
      <guid>https://dev.to/trackjs/building-request-metrics-5437</guid>
      <description>&lt;p&gt;We’ve been working on something big. We’re &lt;strong&gt;&lt;a href="https://requestmetrics.com/"&gt;building Request Metrics&lt;/a&gt;&lt;/strong&gt;, a new service for web performance monitoring.&lt;/p&gt;

&lt;p&gt;TrackJS is a fantastic tool to understand web page errors, but what if your pages aren’t broken, just slow? What if the checkout page takes 10 seconds to load? What if that user API is slowing down from your recent database change? What pages have the worst user experience? Request Metrics will tell you that.&lt;/p&gt;

&lt;p&gt;“So what Todd, there’s lots of performance monitoring tools available.” Yes, but they suck. Today’s performance tools require too much configuration and setup. There’s mountains of data to store, dozens of knobs to turn, and alerts to configure. You spend days getting them working, only to have pretty charts that don’t actually tell you anything or dense query languages that you’ll never fully understand.&lt;/p&gt;

&lt;p&gt;And you get to pay thousands of dollars for them too!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Request Metrics is going to be the fastest, the simplest, and probably the cheapest performance monitoring tool ever.&lt;/em&gt; Request Metrics will natively expose the most important performance information. It will automatically alert you when you need to pay attention. And all you need to do is paste our agent in your page.&lt;/p&gt;

&lt;p&gt;Plus, it’s going to be cheap enough that any team can use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Best Part
&lt;/h2&gt;

&lt;p&gt;The best part is that you get to see how we build it! We’ve been recording the development of Request Metrics and publishing episodes for each topic we tackle. You can see how we &lt;a href="https://requestmetrics.com/making-of/episode-1-file-new-project"&gt;started the project with .NET Core&lt;/a&gt;, how we &lt;a href="https://requestmetrics.com/making-of/episode-3_5-basic-ansible-with-ssh-keys"&gt;configured our first Linux server with Ansible&lt;/a&gt;, and how we &lt;a href="https://requestmetrics.com/making-of/episode-1-file-new-project"&gt;build and deploy the code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our first 8 episodes are live now on &lt;a href="https://www.youtube.com/channel/UCIklNDcnPT8_eVFM1oOoQyA"&gt;our YouTube channel&lt;/a&gt;, with new releases every week. Subscribe to it for updates, or &lt;a href="https://requestmetrics.com/newsletter/"&gt;join the Request Metrics newsletter&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Development is considerably farther ahead of the videos (editing takes a long time). And we’re already testing things internally. It’s so good. We’re going to open it up for beta users in a few weeks, and &lt;a href="https://requestmetrics.com/newsletter/"&gt;Request Metrics subscribers&lt;/a&gt; will be the first to know. So be sure to join.&lt;/p&gt;

</description>
      <category>javascriptwebdevtutorial</category>
    </item>
    <item>
      <title>Powerful Ignore Rules for Noisy JavaScript Errors</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Mon, 02 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/powerful-ignore-rules-for-noisy-javascript-errors-19j</link>
      <guid>https://dev.to/trackjs/powerful-ignore-rules-for-noisy-javascript-errors-19j</guid>
      <description>&lt;p&gt;Ignoring noisy and external errors is important to understanding the health of your client-side applications. Third-party scripts, user extensions, content crawlers, and non-impactful errors create lots of noise in web operations. With TrackJS Ignore Rules, you can filter out this noise and and have a clear view of your web application quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dC2IFGI---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/DA83EF95-9FE2-40C7-B853-736BCD5668B6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dC2IFGI---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/DA83EF95-9FE2-40C7-B853-736BCD5668B6.png" alt="Silence Unimportant Errors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can create &lt;strong&gt;unlimited Ignore Rules&lt;/strong&gt; with all TrackJS accounts. We won’t limit your ability to filter out noise, and get better information. Ignore rules are powerful and give you options to see the information that’s most relevant to you.&lt;/p&gt;

&lt;p&gt;Ignore Rules are applied to incoming errors by our system &lt;strong&gt;before&lt;/strong&gt; your account’s limits are applied. Creating Ignore Rules helps you capture more data that’s relevant to your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multiple Rule Conditions
&lt;/h2&gt;

&lt;p&gt;The first thing you’ll notice when adding a new Ignore Rule is that it looks a lot like the TrackJS global filter. You can use the controls to add multiple &lt;em&gt;conditions&lt;/em&gt; to your Ignore rule across 9 different fields relevant to your errors.&lt;/p&gt;

&lt;p&gt;Multiple conditions are logically “OR” within a field, and logically “AND” between fields. For example, you can ignore the error message “console is not defined” on browsers “IE 8” or “IE 9”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Csrbw1fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/039EA325-93DD-46F0-B4A3-5603287EC7C8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Csrbw1fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/039EA325-93DD-46F0-B4A3-5603287EC7C8.png" alt="Ignore Rule for Unsupported Browsers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also create Ignore Rules using custom Metadata conditions, which are treated a bit differently. Metadata conditions are logically “OR” within a Metadata key and logically “AND” if you specify different keys. For example, you can ignore errors that come from “version 1” or “version 2” as well as originated from “server x”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ipzOvsmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/536EEED1-247B-4C2D-8AB1-1D73A344B630.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ipzOvsmM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/536EEED1-247B-4C2D-8AB1-1D73A344B630.png" alt="Ignore Rule by Metadata"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also create Ignore Rules by the error Stack Trace. This allows you to drill into third-party errors that inject into the page, such as the Facebook widget. The Stack Trace condition allows you to ignore errors that reference “connect.facebook.net/sdk.js“.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ignore Rule Preview
&lt;/h2&gt;

&lt;p&gt;After adding conditions to your Ignore Rule, we’ll calculate how many errors will be affected below the form. When you save an Ignore Rule, existing errors in your account will be deleted, and future errors will be discarded. You can click “Show Details” to see a breakout of how many errors will be deleted&lt;/p&gt;

&lt;h2&gt;
  
  
  Discoverable Rules
&lt;/h2&gt;

&lt;p&gt;TrackJS helps you discover the Ignore Rules you need to tune your account with Suggested Rules and Conditions. When you open Suggested Rules, we’ll look for common noisy errors like “Script Error” and Googlebot browser. If we find these patterns, you can quickly filter out these noisy problems.&lt;/p&gt;

&lt;p&gt;We’ll also look at the most frequently occurring errors in each of your Applications, and give you suggestions to ignore them if they are non-impactful errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tPLp4gL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/3E729BBA-21E2-49E9-B850-067A56A0E68C.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tPLp4gL2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/3E729BBA-21E2-49E9-B850-067A56A0E68C.png" alt="Ignore Rule Suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, whenever you are creating an Ignore Rule, we’ll suggest conditions for each field based on what the most frequently occurring values are.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0iLIAa01--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/AF084C24-FC50-4122-A6A6-D1DAE55975F6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0iLIAa01--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/AF084C24-FC50-4122-A6A6-D1DAE55975F6.png" alt="Ignore Condition Suggestions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create Ignore Rules from Reports
&lt;/h2&gt;

&lt;p&gt;You can create Ignore Rules from anywhere you see noise in your TrackJS account, including the aggregated reports, rollup reports, and error details.&lt;/p&gt;

&lt;p&gt;From any aggregated report, select the items you want to ignore and click the Ignore button. We’ll pre-build the conditions to Ignore and remove those errors from your account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hS5yCwSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/2AE17A70-BDFF-4C4D-8E31-A8DA27F42A7A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hS5yCwSG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/2AE17A70-BDFF-4C4D-8E31-A8DA27F42A7A.png" alt="Ignore from Aggregated Report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also Ignore from the rollup report or error details report by hitting the “Ignore” button in the toolbar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UMIZ2J11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/5FC095A3-E2D2-4963-8483-12FE44881788.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UMIZ2J11--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/5FC095A3-E2D2-4963-8483-12FE44881788.png" alt="Ignore from Rollup and Details Report"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitor Your Running Ignore Rules
&lt;/h2&gt;

&lt;p&gt;Once you have some Ignore Rules running, you can see how they are being applied. Each rule is shown in a table with the name, applications, conditions applied, and the status. The status includes a count of how many errors have been ignored by this rule in the last 24 hours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r2T6Ev76--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/43A6B156-BDB1-49AE-A65E-6349513FE926.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r2T6Ev76--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-12-ignore-rules/43A6B156-BDB1-49AE-A65E-6349513FE926.png" alt="Ignore Rule Status"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you have any questions or concerns with how to use TrackJS Ignore Rules, please &lt;a href="//mailto:hello@trackjs.com"&gt;let us know&lt;/a&gt;! Our engineering team directly supports the product, and we pride ourselves in providing the best service to our customers.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>errors</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Dumpster-Fire Alert for Your JavaScript Errors</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Tue, 12 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/a-dumpster-fire-alert-for-your-javascript-errors-48lk</link>
      <guid>https://dev.to/trackjs/a-dumpster-fire-alert-for-your-javascript-errors-48lk</guid>
      <description>&lt;p&gt;Do you work with an app that’s a dumpster-fire of errors? Wishing for an appropriate alert when you need to fight down the flames? Look no further friend. Today, we’re creating a Dumpster fire notification for your JavaScript errors with &lt;a href="https://www.particle.io/" rel="noopener noreferrer"&gt;Particle&lt;/a&gt; and &lt;a href="https://trackjs.com/" rel="noopener noreferrer"&gt;TrackJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My friend &lt;a href="https://twitter.com/gelicia" rel="noopener noreferrer"&gt;Kristina&lt;/a&gt; is a wizard with hardware and LEDs. Awhile back, she made the dumpster fire to present at a conference, and she printed an extra one for me! Today, we’re going to set up the hardware, configure the software, and integrate it with our errors.&lt;/p&gt;

&lt;p&gt;Credit for this goes to &lt;strong&gt;Kristina Durivage&lt;/strong&gt; , who did the vast majority of the work, I just tweaked the software here and there.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hardware
&lt;/h2&gt;

&lt;p&gt;The dumpster itself was 3D printed from &lt;a href="https://www.thingiverse.com/thing:950602" rel="noopener noreferrer"&gt;Thingiverse&lt;/a&gt;, printed with translucent filament so the fire light will shine through. It is powered by a &lt;a href="https://store.particle.io/collections/wifi/products/photon" rel="noopener noreferrer"&gt;Particle Photon&lt;/a&gt; with a WS2812 LED strip. Added some acrylic batting as the garbage to diffuse the light.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgsv6eaw3ywo64ithez7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgsv6eaw3ywo64ithez7.jpg" alt="Dumpster Hardware" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Firmware
&lt;/h2&gt;

&lt;p&gt;We need to load some firmware on our Photon device. Luckily, Kristina left me some detailed notes on cat stationary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freddta6p5ddqj6ce3ezr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Freddta6p5ddqj6ce3ezr.jpg" alt="Kristina's Instructions" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d never used Particle before, so first I need to create an account and explore the UI a bit. Starting up and adding my device was pleasantly easy and straightforward. I only broke-down and read the documentation once! (The &lt;a href="https://docs.particle.io/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; was pretty good too).&lt;/p&gt;

&lt;p&gt;Now that I had an account and a device, it was time to write some code. I used the Particle Web IDE, which was surprisingly good. I created the &lt;code&gt;dumpsterfire&lt;/code&gt; application and pasted in the source from &lt;a href="https://github.com/gelicia/trackjs-dumpsterfire" rel="noopener noreferrer"&gt;Kristina’s dumpster fire project&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The firmware code is basically a &lt;code&gt;setup&lt;/code&gt; function that initializes the device and sets up actions, and a &lt;code&gt;loop&lt;/code&gt; function, which will run endlessly.&lt;/p&gt;

&lt;p&gt;For our use case, the loop is the visual frame of the fire. Each time the loop runs, the flames will change. This is powered by a dependency on the &lt;code&gt;FastLED&lt;/code&gt; project. Add in dependencies using the “Libraries” option in the menu.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxwbvyyo9dwt4m3432yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faxwbvyyo9dwt4m3432yk.png" alt="Dumpster Firmware" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What starts the dumpster fire though? I need to check TrackJS periodically to see if there is a dumpster fire of errors needing my attention. The firmware does this with the &lt;code&gt;errorPollingTimer&lt;/code&gt;, which is setup to run &lt;code&gt;pollForErrorCount&lt;/code&gt; every minute. That function serializes the TrackJS credentials and query time range as JSON, and publishes an event.&lt;/p&gt;

&lt;p&gt;In a moment, we’ll create the webhook that listens for that event and returns an error count event as &lt;code&gt;error_count&lt;/code&gt;. The firmware listens for that response with &lt;code&gt;errorCountHandler&lt;/code&gt;, which checks if it’s greater than some threshold, and starts the bin on fire.&lt;/p&gt;

&lt;p&gt;To get it all working, I added my TrackJS customerID, API Key, application key, and maximum error threshold to the firmware. You can get this all from your &lt;a href="https://my.trackjs.com/Account/Organization" rel="noopener noreferrer"&gt;TrackJS account&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Webhook
&lt;/h2&gt;

&lt;p&gt;The webhook runs in the Particle cloud and glues our device Firmware to the TrackJS API. Specifically, it listens for the &lt;code&gt;get_error_count&lt;/code&gt; event from the firmware and makes an HTTPS request to the TrackJS API with the data provided. It parses out the &lt;code&gt;totalCount&lt;/code&gt; of errors returned and fires it back to the firmware as an &lt;code&gt;error_count&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;There’s a UI to create the webhook in the Particle Console, but it’s a lot easier to just push the configuration to your account with the Particle API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ 
  "event": "get_error_count", 
  "responseTopic": "error_count", 
  "errorResponseTopic": "error_count_fail", 
  "integration_type": "Webhook", 
  "url": "https://api.trackjs.com/{{{customerId}}}/v1/errors/", 
  "requestType": "GET", 
  "headers": { 
    "Authorization": "{{{apiKey}}}" 
  }, 
  "query": { 
    "size": "1", 
    "startDate": "{{{startDate}}}", 
    "endDate": "{{{endDate}}}", 
    "application": "{{{application}}}" 
  }, 
  "noDefaults": true, 
  "responseTemplate": "{{{metadata.totalCount}}}" 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the webhook started running and the device booted, I saw a stream of events coming into my Particle console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysb81ii5cxjr9t7p8opy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fysb81ii5cxjr9t7p8opy.png" alt="Dumpster Polling Events" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the dumpster started on fire. Burn baby burn.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn3n6gz7wcd4wwb2sljc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdn3n6gz7wcd4wwb2sljc.gif" alt="Dumpsterfire in action" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This was a fun project from Kristina Durivage. We integrated an important feed of information from &lt;a href="https://dev.toh"&gt;TrackJS about our production errors&lt;/a&gt; into a wonderfully funny real-world alert. If you’d like to build your own dumpster fire, let us know! All the links and code is available, linked from this post.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>errors</category>
      <category>webdev</category>
      <category>iot</category>
    </item>
    <item>
      <title>The Ongoing State of JavaScript Errors</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Mon, 04 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/the-ongoing-state-of-javascript-errors-3nob</link>
      <guid>https://dev.to/trackjs/the-ongoing-state-of-javascript-errors-3nob</guid>
      <description>&lt;p&gt;Today, we’re releasing &lt;a href="https://dev.to/global-stats/"&gt;TrackJS Global Error Statistics&lt;/a&gt; to the public. This aggregated production data is a useful measure of &lt;strong&gt;the state of client-side JavaScript errors and the quality of the web&lt;/strong&gt;. We break it down by the most common errors, browsers, and operating systems.&lt;/p&gt;

&lt;p&gt;We did this a few years ago with the &lt;a href="https://dev.to/blog/the-state-of-client-side-javascript-errors/"&gt;State of Client-Side JavaScript Errors&lt;/a&gt;. It was quite useful, but very time consuming to produce. We haven’t had time to do it again since 2015, with all the other things we’ve been building.&lt;/p&gt;

&lt;p&gt;But this time is different. We built the reports to calculate everything automatically. Our system calculates aggregate metrics and publishes them every week, and the &lt;a href="https://dev.to/global-stats/"&gt;error statistics report&lt;/a&gt; parses out some numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-11-04-global-javascript-error-statistics/global-errors.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq4oxkezjptizmk96wq3f.png" alt="Global Error Statistics" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We’ve been aggregating data since early September, so we don’t have a lot of history yet. But as we gather more, the report will become more useful. When you feel like the web is getting buggier, we’ll have objective data for you to reference.&lt;/p&gt;

&lt;p&gt;The report also pulls data on the most common errors. I review that data and write summaries about the error, and why they happen. No surprise, the #1 error continues to be &lt;code&gt;Script Error&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As patterns develop in the report, we’ll be writing a lot more about the global error data and what it means. If there is something you’d like to see, please &lt;a href="//mailto:hello@trackjs.com"&gt;let us know!&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>errors</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>errormonitoring</category>
    </item>
    <item>
      <title>What is Developer Time Worth?</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Tue, 15 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/what-is-developer-time-worth-10im</link>
      <guid>https://dev.to/trackjs/what-is-developer-time-worth-10im</guid>
      <description>&lt;p&gt;It’s remarkable to me how many developers have no idea what their time is worth. I speak with a lot of developers, and when I mention my work on TrackJS, I frequently hear “I could build that”. Yeah, you could. Observability tools aren’t rocket science. But you shouldn’t. Your time is too valuable to build better mousetraps.&lt;/p&gt;

&lt;p&gt;Your time is valuable and finite. Both to &lt;em&gt;you&lt;/em&gt; and to &lt;em&gt;your company&lt;/em&gt;. Your time should be spent on the work that will be the most impactful and valuable. The &lt;a href="https://en.wikipedia.org/wiki/Pareto_principle"&gt;Pareto Principle&lt;/a&gt; tells us that most of your value will come from 20% of the work.&lt;/p&gt;

&lt;p&gt;By focusing your attention on the right 20%, you can make a bigger impact, create more value, and be more successful. Recreating tools that already exist is probably not the work that will create value for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Your Time is Worth to Your Employer
&lt;/h2&gt;

&lt;p&gt;In a perfect world, your company pays you fairly for what your time is worth to them, but that depends a bit on where you live. Within the US, we have some data on web developer salaries from the &lt;a href="https://www.bls.gov/oes/current/oes151134.htm"&gt;U.S. Bureau of Labor Statistics&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--O9KVcKXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-10-15-what-is-developer-time-worth/annual-mean-wage.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--O9KVcKXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://trackjs.com/assets/images/blog/2019-10-15-what-is-developer-time-worth/annual-mean-wage.png" alt="Annual Mean Wage of Web Developers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you live in a major software center like New York, Austin, or Minneapolis, the mean salary is somewhere around $90K. If we add another 25% for the cost of benefits and employment overhead, and we have about $112K.&lt;/p&gt;

&lt;p&gt;That’s $56/hour on average. Maybe you make less, hopefully you make more, but its a good estimate for what your time &lt;em&gt;costs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;cost&lt;/em&gt; of your time is interesting as a minimum threshold. Your time is worth at least that much, hopefully quite a bit more. Exactly how much more depends on your opportunity. What could you be creating with your time?&lt;/p&gt;

&lt;p&gt;I’ve worked on a project that generated over $10 million in gross profit. It took roughly 8,000 hours to build. Our time was &lt;em&gt;worth&lt;/em&gt; $1250 per hour!&lt;/p&gt;

&lt;h2&gt;
  
  
  What Your Time is Worth to You
&lt;/h2&gt;

&lt;p&gt;You have 2,150 weeks. That’s every week of your working life, age 22 to 65. That’s your time to make an impact in your professional life. Time is our most precious and most fleeting resource. We can’t get our time back, we can’t buy more of it. We can only choose what to spend it on.&lt;/p&gt;

&lt;p&gt;You can choose the work that you believe in. You can choose the companies, the projects, and the people that are making an impact; the work that creates lasting value.&lt;/p&gt;

&lt;p&gt;Or you can choose to write your own JavaScript Framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Your Worth
&lt;/h2&gt;

&lt;p&gt;As a web developer, your professional time is worth somewhere between $56 and $1500 per hour. It’s up to you to decide how to spend it.&lt;/p&gt;

&lt;p&gt;When I talk about TrackJS and someone tells me “I’m building my own front end monitoring tools”, they probably don’t know what their time is worth. Creating your own is deciding to spend 4 weeks, costing $9,000, to get a less-complete copy of a $100 software package. You’re wasting thousands of dollars and hundreds of precious hours.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mo26qYJE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://trackjs.com/assets/images/blog/2019-10-15-what-is-developer-time-worth/moneyfire.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mo26qYJE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://trackjs.com/assets/images/blog/2019-10-15-what-is-developer-time-worth/moneyfire.gif" alt="Fueling the Money Fire"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even more foolish, you could have spent your time building something impactful for your company. You could have launched a new feature, landed a new customer, or solved a new problem. You could have created $200,000 of value focusing on other opportunities.&lt;/p&gt;

&lt;p&gt;Don’t waste your precious time trying to avoid spending a few dollars tools. Don’t be penny-wise and pound-foolish.&lt;/p&gt;




&lt;p&gt;TrackJS can help you understand how your web application breaks in production. &lt;a href="https://TrackJS.com/"&gt;TrackJS saves you hundreds of hours debugging&lt;/a&gt; for only a few bucks per month. That’s a lot of value. You go be awesome and build the best web app you can, we can cover your monitoring.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>timemanagement</category>
    </item>
    <item>
      <title>Faster Elasticsearch Query Performance</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Wed, 09 Oct 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/faster-elasticsearch-query-performance-3855</link>
      <guid>https://dev.to/trackjs/faster-elasticsearch-query-performance-3855</guid>
      <description>&lt;p&gt;We store all of our JavaScript error data in a large Elasticsearch cluster. This lets our customers slice and dice their error data in realtime, and perform full text searches over it. We push Elasticsearch to its limit, and we recently started querying more data for some of our core pages. We noticed that a certain set of our customers started experiencing unacceptably slow page response times. This is how we tracked down the problem and fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggregations: GROUPBY in Elasticsearch
&lt;/h2&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/es-perf/errors.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvtf2qwwy6pjy8pl6gbc.png" alt="JavaScript errors grouped by message" width="800" height="470"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you visit the “Errors” page in TrackJS we show you a paginated list of error messages and the number of times each one occurred. You can sort by most recently seen errors, the total number of errors, or number of unique users impacted. Essentially we’re grouping errors by their messages. In a relational database you’d do this with a &lt;code&gt;GROUP BY&lt;/code&gt; clause. In Elasticseach this is called a &lt;code&gt;Terms Aggregation&lt;/code&gt;. We’re essentially doing the same thing though - grouping a bunch of things by a single field (error message in this case).&lt;/p&gt;

&lt;p&gt;But we can go further in Elasticsearch, and perform nested aggregates (groupings). For example, for each error message group we can also retrieve the number of unique browsers, urls, and users impacted, along with the versions of your code affected and a nice date histogram of occurrences of this group over time. We can get all of that for each item in our grouped list! This would be very difficult to do with SQL in a traditional database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grouping on High Cardinality Fields
&lt;/h2&gt;

&lt;p&gt;Whenever you’re grouping instances of things by a certain field, the number of distinct field values plays a role in how fast that query will execute. Said another way, the query time will be directly proportional to the &lt;a href="https://en.wikipedia.org/wiki/Cardinality" rel="noopener noreferrer"&gt;cardinality&lt;/a&gt; of the field being grouped. For instance, if you have a dataset with a million errors, but there are only 5 unique error messages, the message aggregate query will be very fast. There are only five possible groupings after all. On the flip side, if you can imagine the worst case, where every error message is distinct, every error message will be its own group and the query will be slow.&lt;/p&gt;

&lt;p&gt;In our case it was these high cardinality customers that were experiencing slow response times. Their error messages contained URLs, and those URLs contained query string params with unique identifiers, so in effect every error message was different. When you’ve got hundreds of thousands of distinct error messages, that is going to be an expensive grouping operation! Given the realities of JavaScript error data though, we needed to figure out a way to speed things up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aggregating Faster
&lt;/h2&gt;

&lt;p&gt;So our goal is fast error message grouping. The problem is JavaScript error messages can be variable length, and sometimes thousands of characters long. In Elasticsearch, aggregating over long strings is slower than aggregating over numeric values. Said another way, it’s faster to group by &lt;code&gt;long&lt;/code&gt; values than it is &lt;code&gt;string&lt;/code&gt; values. Wouldn’t it be great if we could aggregate over a numeric field instead of a string field? But how do we turn an error message in to a number?&lt;/p&gt;

&lt;p&gt;We hash it!&lt;/p&gt;

&lt;p&gt;We take all incoming error messages and hash them with the &lt;a href="https://en.wikipedia.org/wiki/MurmurHash" rel="noopener noreferrer"&gt;MurmurHash&lt;/a&gt; algorithm. We store the resulting 64-bit hash as a &lt;code&gt;long&lt;/code&gt; inside Elasticsearch. This lets us group on a number field instead of a string field. There’s some gymnastics involved to turn a hash back to a string message, but that’s for another time.&lt;/p&gt;

&lt;p&gt;The problem was, we were already using this trick to do aggregates, and we were still seeing slowness. And more concerning, we were seeing a huge increase in the amount of RAM required to handle each query. What else was going on?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Culprit: Nested Aggregates
&lt;/h2&gt;

&lt;p&gt;In order to surface even more meaningful data for our customers, we recently added 5 more nested aggregates to some of our core queries. That meant we’d first group all errors by error message, then we’d take each of those groups and calculate sub-groupings for the 5 nested aggregate fields (groups of groups).&lt;/p&gt;

&lt;p&gt;Imagine you have 1,000,000 errors with 1,000 distinct error messages between them. You want to group all instances of the errors by message, and then for each message group also find some sub-aggregates (number of users for that message, browsers, urls etc), and then order them by highest number of occurrences.&lt;/p&gt;

&lt;p&gt;Then you want to return just the first page of results, maybe 20-100 of them.&lt;/p&gt;

&lt;p&gt;If you ask Elasticsearch to do that in one query, here’s what you get:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Group all error messages together so you have an in-memory list of 1,000 message groups. (So far this is not too bad since we aggregate on the hash field value)&lt;/li&gt;
&lt;li&gt;Then, for each error message group, do the sub-groupings. This will necessitate many passes over the various field indexes of 1M errors. It will also explode the amount of memory needed to satisfy the query, as this is all being kept memory-resident.&lt;/li&gt;
&lt;li&gt;Once all groups and sub-groups have been calculated, order by message count. (again, to handle sorting we need the entire list of 1,000 groups in memory)&lt;/li&gt;
&lt;li&gt;Return the top 20, throwing away the other 980 aggregates&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is a lot of work being done that just gets thrown away. We are calculating sub-groups for hundreds of message groupings that we will never show the user. This is taking time, and eating memory!&lt;/p&gt;

&lt;h2&gt;
  
  
  Two Queries Are Better Than One
&lt;/h2&gt;

&lt;p&gt;So instead of one big query, we decided to see what would happen if we made two passes. For the first query, we just retrieve the message groupings and do the sorting. We figure out which 20 error messages we’re going to show the user. This still takes time proportional to the error message cardinality, but we’re not paying for all the nested aggregates. For the second query, we enrich those 20 message groups with all the sub-group information, like date histogram, browsers impacted etc. It’s much faster to find sub-aggregates for 20 specific messages rather than all 1,000.&lt;/p&gt;

&lt;p&gt;There’s a bit more code complexity involved with this approach since we’re making multiple queries and stitching the results together, but the performance improvements are impressive.&lt;/p&gt;

&lt;p&gt;For our customers with normal error message cardinality, they won’t notice much of a difference. The two-query approach performs roughly the same as the single query for average datasets (the overhead of the second query negates any speed improvements). However, for our customers with large cardinality datasets, they will see an order of magnitude speedup in some cases! We think adding some application complexity is a worthwhile tradeoff to improve our customer experience!&lt;/p&gt;

&lt;p&gt;We are always working on ways to surface more data and improve the performance of our application. Feel free to &lt;a href="https://my.trackjs.com/signup" rel="noopener noreferrer"&gt;sign up and give TrackJS a try today&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>elasticsearch</category>
      <category>javascript</category>
      <category>debugging</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Debugging: "Cannot read property 'length' of undefined."</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Mon, 30 Sep 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/debugging-cannot-read-property-length-of-undefined-21e0</link>
      <guid>https://dev.to/trackjs/debugging-cannot-read-property-length-of-undefined-21e0</guid>
      <description>&lt;p&gt;While looking into an &lt;a href="https://trackjs.com/blog/debugging-edge-failed-to-construct-request-invalid-argument/" rel="noopener noreferrer"&gt;issue with Microsoft Edge and the Facebook sdk&lt;/a&gt; a few weeks ago, we ran into a very common error: &lt;code&gt;Cannot read property ‘length’ of undefined&lt;/code&gt;. In fact, this is the 6th most common error, affecting nearly 28% of accounts.&lt;/p&gt;

&lt;p&gt;This error indicates that our code expects to have an object with a &lt;code&gt;length&lt;/code&gt; property, but that object was not present. &lt;code&gt;length&lt;/code&gt; is commonly used on &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;array&lt;/code&gt;, but a custom object could also have this property.&lt;/p&gt;

&lt;p&gt;This is a &lt;strong&gt;blocking error&lt;/strong&gt; , and execution will stop. It is important to defensively typecheck data passed in from external scripts and systems before interacting with them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause
&lt;/h2&gt;

&lt;p&gt;This error can be thrown for a lot of reasons, as it is incredibly common to reference the &lt;code&gt;length&lt;/code&gt; property of &lt;code&gt;string&lt;/code&gt; or &lt;code&gt;array&lt;/code&gt; during everyday development.&lt;/p&gt;

&lt;p&gt;In our case, we were &lt;a href="https://trackjs.com/blog/how-to-wrap-javascript-functions/" rel="noopener noreferrer"&gt;wrapping a JavaScript function&lt;/a&gt; to intercept &lt;code&gt;fetch&lt;/code&gt; requests for instrumentation, and we had expected the &lt;code&gt;url&lt;/code&gt; property as defined in the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch" rel="noopener noreferrer"&gt;fetch specification&lt;/a&gt; would be a string.&lt;/p&gt;

&lt;p&gt;The Facebook sdk didn’t call &lt;code&gt;fetch&lt;/code&gt; with a string. They called it with a serializable object. 🤦‍♂️.&lt;/p&gt;

&lt;p&gt;They had built an object similar to the &lt;a href="https://nodejs.org/api/url.html" rel="noopener noreferrer"&gt;nodejs Url class&lt;/a&gt;, which provides some easier access and utilities to build up a url string. The custom object could be serialized as a url with the implementation of a custom &lt;code&gt;toString&lt;/code&gt; function. Here is a simplistic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;example.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;}${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passing a serializable object into fetch is not in the specification, however it seems to work in all the modern browsers.&lt;/p&gt;

&lt;p&gt;Due to the nature of our wrapping of &lt;code&gt;fetch&lt;/code&gt;, we assumed url to be a different type, and threw an error trying to get the length of something that wasn’t a string.&lt;/p&gt;

&lt;p&gt;In my opinion, it would have been better to serialize their url object to a string literal &lt;em&gt;before&lt;/em&gt; calling &lt;code&gt;fetch&lt;/code&gt;, and not rely on &lt;em&gt;undocumented behavior&lt;/em&gt; from the browsers. But you can’t rely on external teams to always make sound technical decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Fix
&lt;/h2&gt;

&lt;p&gt;Always defensively check data from external sources, which include api requests, network responses, and function calls from other scripts. If you accept a &lt;code&gt;string&lt;/code&gt; value, this can take a few different forms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A String Literal &lt;code&gt;"like this"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A String Object &lt;code&gt;new String("like this")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A Serializable Object &lt;code&gt;{ toString: () =&amp;gt; "like this" }&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, it can also be &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;undefined&lt;/code&gt;, or a totally different unsupported type as well. In most cases, we can simply coerce the value to a string, which will guarantee our string functions work.&lt;/p&gt;

&lt;p&gt;Coercing the value to a string is not complicated, and you don’t have to check for all the variations it could be. Let the runtime do that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unknownStringVar&lt;/span&gt; &lt;span class="nx"&gt;stringy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;knownStringVar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;stringy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
  &lt;span class="c1"&gt;// go about your day &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will serialize string literals, objects, numbers, booleans, and serializable objects into a plain-old string literal that we can safely get the &lt;code&gt;length&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;JavaScript can fail in lots of interesting ways. Maybe you can’t get the length of undefined, or maybe that network request is sporadically failing in production. &lt;a href="https://trackjs.com/" rel="noopener noreferrer"&gt;Front-end error monitoring&lt;/a&gt; from TrackJS gives your team insight into production problems, without needing to learn complex logging tools.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>errors</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Lessons Learned From A Buggy React Upgrade</title>
      <dc:creator>Todd H. Gardner</dc:creator>
      <pubDate>Tue, 10 Sep 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/trackjs/lessons-learned-from-a-buggy-react-upgrade-438</link>
      <guid>https://dev.to/trackjs/lessons-learned-from-a-buggy-react-upgrade-438</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is a guest post by &lt;a href="https://dormoshe.io" rel="noopener noreferrer"&gt;Dor Moshe&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://dormoshe.io/articles/top-resources-to-explore-react-fiber-18" rel="noopener noreferrer"&gt;React v16 is innovative&lt;/a&gt;. It comes with &lt;strong&gt;&lt;a href="https://trackjs.com/for/react/" rel="noopener noreferrer"&gt;better error handling&lt;/a&gt; and new features&lt;/strong&gt; like &lt;a href="https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html" rel="noopener noreferrer"&gt;Error Boundaries&lt;/a&gt;, Fragment, Portals, Lazy, Memo, a new Context API, Hooks, Suspense, and concurrent rendering. I have been upgrading a large React code base from &lt;code&gt;React v15&lt;/code&gt; to &lt;code&gt;React v16&lt;/code&gt;. This upgrade was clearly necessary &lt;strong&gt;but implementing is nontrivial&lt;/strong&gt; on a large codebase. Thanks to the React team at Facebook, the migration path looks easy. Unfortunately, this was not the case.&lt;/p&gt;

&lt;p&gt;First, I upgraded the &lt;code&gt;react&lt;/code&gt; and &lt;code&gt;react-dom&lt;/code&gt; libraries to v16 to discover the side effects. The result in the browser was a blank screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/blank-page.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flyt7f2ntblqmezkx00l4.png" alt="Blank page" width="428" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And this was me:&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/me1.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo6251lh0z3zt56l2jkhp.png" alt="Me, confused about what went wrong" width="480" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is not the result you want to see when upgrading a library, especially one you use extensively. After a few seconds, I thought “ok, let’s start to research”.&lt;/p&gt;

&lt;p&gt;In this article, we’ll go through the process of &lt;strong&gt;investigating and figuring out the root cause&lt;/strong&gt; of the problem I had. I’ll share with you &lt;strong&gt;tips and best practices&lt;/strong&gt; on how to investigate a bug, and how to fix it. In addition, I’ll teach you the relevant parts of the &lt;strong&gt;JS ecosystem,&lt;/strong&gt; which are related to my use-case.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip 1: Getting Started
&lt;/h2&gt;

&lt;p&gt;It’s a hard question to answer. There are a few options, and it depends on many factors. When I see a blank page, I try to understand first if I pressed enter in my address bar. Then I try to refresh. Click &lt;code&gt;F12&lt;/code&gt; / Open the dev-tool. Verify all log levels are shown (&lt;code&gt;warning, error, info&lt;/code&gt;). Clear console. Clear networks. Refresh. If I see an exception, I try to figure out the reason by reading the error message. When it’s not enough, I click on the &lt;code&gt;"Pause on exceptions”&lt;/code&gt; button in my dev-tool &lt;code&gt;Source&lt;/code&gt; tab. Then I refresh and continue to check.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use your dev tool. Don’t “console.log” all-day&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Chrome and other browsers’ development teams have been working hard to give us a wonderful debugging experience. They really care about it. Enjoy using it. Try the features. console.log is useful for specific use cases. Don’t misuse it.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/devtools.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxky8kepo5fz7024xw0e5.png" alt="Chrome dev-tool. Network tab." width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Ok, so let’s do it…
&lt;/h3&gt;

&lt;p&gt;So, I clicked &lt;code&gt;F12&lt;/code&gt;. What I saw was the same blank page. &lt;code&gt;F12&lt;/code&gt; didn’t respond. Then I clicked the right button of my mouse. The same. So, I wanted to close the tab. Nothing. My browser was stuck. And this was me:&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/me2.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffyw5ls6vramqu3tj038.png" alt="Me, Angry and Frustrated that the browser was stuck." width="480" height="288"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip 2: Take a Break
&lt;/h2&gt;

&lt;p&gt;Don’t break your keyboard. Your browser gets stuck because people are not machines. Developers make mistakes. It’s reasonable. And if you think “Oh maybe the computer made a mistake, let’s run it again”, you will probably waste your time. &lt;code&gt;1 + 1 is 2&lt;/code&gt;, and it doesn’t matter how many times you run it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your computer doesn’t have dementia&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think that each company has to have a rage room in its office. And this is a great time to go there. If you don’t have one, please calm down, drink water, open your mind, and continue reading.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/rage-room.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fecolvult1vegueb22rhj.png" alt="Rage Room" width="480" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ok, so let’s continue…
&lt;/h3&gt;

&lt;p&gt;The next step I tried is to switch my browser. It didn’t fix the problem, but it can give you more information. My tab was stuck. So it wasn’t a browser-related issue. Here I had an intuition that because of the state of the tab, I had an endless loop. But I didn’t know where. So I decided to sow &lt;code&gt;console.log&lt;/code&gt; and &lt;code&gt;debugger&lt;/code&gt; into the code. This proved a waste of time because I had a huge codebase.&lt;/p&gt;

&lt;p&gt;Then, I went through was to disable big parts of my code. This method gives you more information about the problem because you can eliminate components. But it can produce other bugs and issues which drop you from your way to solve the issue. After a few more hours, I decided to drink a cup of coffee and come back with a different approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  (Big-Mega-Huge) Tip #3: Stop Script Execution
&lt;/h2&gt;

&lt;p&gt;I understood my problem wasn’t going to be solved so soon. I had to try something else. I decided to search on the web &lt;code&gt;“how to stop an endless loop”&lt;/code&gt;. After a few minutes of reading, I found some tricks to use. But they didn’t work for me. Then I found another one  -  there is a button in Chrome’s dev tool called &lt;code&gt;“Pause script execution”&lt;/code&gt;. It’s a toggle button with two states.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/devtools2.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30n59urjoaa8b2jrecyl.png" alt="Chrome dev-tools. Source tab" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was familiar with one state  -  &lt;code&gt;“Resume script execution”&lt;/code&gt;. This is the button I click when I stop on a breakpoint and want to continue to the next breakpoint. I had never known what happens when I click on it while the code is running. The result was amazing  -  I had succeeded in stopping the loop. And this was the section of code (after removing unnecessary lines of code):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;doneRendering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&gt;//... doneRendering = true; &lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt; 

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;doneRendering&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The debugger stopped at line 8: &lt;code&gt;while (!doneRendering)&lt;/code&gt;. And this was me:&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/me3.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgi2meefmiv4dvudyfzqc.png" alt="Me, declaring victory!" width="480" height="320"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip 4: Know Your Ecosystem
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JavaScript is single-threaded&lt;/strong&gt;. We have one thread for both the code and the UI. If our thread is too busy running our code, the UI isn’t responding. What does ‘too busy’ mean? Using synchronous code means that our UI can respond only when the code finishes running. Our UI interaction is event-driven. Event handlers (functions) will be entered in the &lt;strong&gt;callback queue&lt;/strong&gt; displayed below along with another crucial building block in the JS mechanism  - the &lt;strong&gt;call stack&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="/assets/images/blog/2019-09-lessons-learned-from-a-buggy-react-upgrade/ecosystem.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xvalf7lzjnw717f3ntm.png" alt="The JS mechanism and the Event Loop" width="777" height="577"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a function is called, it moves to the call stack. When a function finishes running, it pops out of the call stack. &lt;strong&gt;The Event Loop is in charge of managing this mechanism.&lt;/strong&gt; When the call stack is empty, i.e., all our synchronous code finishes running, the event loop takes a function from the queue, runs it and puts it in the call stack. When this function ends running, it happens again with the next function in the callback queue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip 5: Don’t Use Busy Waiting in JavaScript
&lt;/h2&gt;

&lt;p&gt;Functions inside the callback queue wait to be moved to the call stack. This means that when we run a synchronous loop like in our case, all the UI interactions and other asynchronous callbacks are in “waiting mode”.&lt;/p&gt;

&lt;p&gt;Let’s go back to our code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;doneRendering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="c1"&gt;//... &lt;/span&gt;
  &lt;span class="nx"&gt;doneRendering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt; 

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;doneRendering&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This section of code demonstrates ‘ &lt;strong&gt;busy waiting’&lt;/strong&gt;. It’s a real code example. Busy waiting is a &lt;strong&gt;technique&lt;/strong&gt; in which a code repeatedly checks if a condition is true. Here we have a loop which &lt;strong&gt;will not let any&lt;/strong&gt;  &lt;strong&gt;other line of code run except code inside the loop&lt;/strong&gt;. Our loop is empty. If &lt;code&gt;doneRendering&lt;/code&gt; is &lt;code&gt;false&lt;/code&gt;, we are stuck forever, and our browser is stuck. And this is the case in my code. Busy waiting is bad practice.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t use busy waiting in JS&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Well, the big open question is how the code worked before React 16? The callback was called &lt;strong&gt;synchronously&lt;/strong&gt; before the loop, so &lt;code&gt;doneRendering&lt;/code&gt; was true. &lt;strong&gt;This loop condition was never satisfied in React v15. I.e., the callback was called synchronously with v15.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Tip 6: Make it Asynchronous
&lt;/h2&gt;

&lt;p&gt;Do you want your users to be stuck with a blank page? Do you want to hold up the single thread you have? You are in the JS world. You have only one thread. In the browser, it’s the thread which also handles the UI. If you use busy waiting,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your UI isn’t responding&lt;/li&gt;
&lt;li&gt;Your UI isn’t visible&lt;/li&gt;
&lt;li&gt;Your browser is stuck&lt;/li&gt;
&lt;li&gt;Your user is out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do you do when you see a blank page? Leave the website. What do you do when your browser is stuck? Leave the website and curse. Let’s use asynchronous code to fix our problem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="c1"&gt;//... &lt;/span&gt;
      &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; 
    &lt;span class="p"&gt;});&lt;/span&gt; 
  &lt;span class="p"&gt;});&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our function returns a promise which will be resolved when the callback will be called. That’s all. No busy waiting. No blank page. No stuck browser. Free day. Happy day.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;During this journey, we have gone through my React v16 migration use case. It might sound too specific at the start, but it isn’t. This is a common experience for a developer. Trying to understand what is the bug. There are a lot of ways to investigate a bug. There are a lot of ways to solve a bug. Know your &lt;strong&gt;arsenal of options&lt;/strong&gt; , including &lt;a href="https://trackjs.com/for/react/" rel="noopener noreferrer"&gt;production error monitoring for your react application from TrackJS&lt;/a&gt;. Choose your &lt;strong&gt;pattern&lt;/strong&gt;. Use your &lt;strong&gt;tool-set&lt;/strong&gt;. Know its features. Understand your language’s &lt;strong&gt;ecosystem&lt;/strong&gt;. Believe there is &lt;strong&gt;gray&lt;/strong&gt;. And don’t forget  - from time to time, &lt;strong&gt;visit a rage room&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
