PageSourceSearch

https://ankitmohanty.vercel.app/articles/forecast-cloudy

html ankitmohanty.vercel.app collected 2026-10-03 06:06:01 UTC 18,353 bytes, 143 lines download raw bytes

1<!DOCTYPE html><html class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><title>Understanding JavaScript Asynchronous Behavior</title><meta name="robots" content="index,follow"/><meta name="description" content="A deep dive into how JavaScript handles asynchronous operations, from callbacks to Promises to async/await."/><meta property="og:title" content="Understanding JavaScript Asynchronous Behavior"/><meta property="og:description" content="A deep dive into how JavaScript handles asynchronous operations, from callbacks to Promises to async/await."/><meta property="og:url" content="https://brian.dev/articles/forecast-cloudy"/><meta property="og:image" content="https://og.brian.dev/api/og?title=Understanding JavaScript Asynchronous Behavior&amp;desc=A deep dive into how JavaScript handles asynchronous operations, from callbacks to Promises to async/await."/><meta property="og:image:alt" content="Og Image Alt"/><meta property="og:image:type" content="image/jpeg"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="600"/><meta property="og:site_name" content="brian.dev"/><link rel="canonical" href="https://brian.dev/articles/forecast-cloudy"/><meta name="next-head-count" content="15"/>
1<script>
2  let darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
3
4  updateMode()
5  darkModeMediaQuery.addEventListener('change', updateModeWithoutTransitions)
6  window.addEventListener('storage', updateModeWithoutTransitions)
7
8  function updateMode() {
9    let isSystemDarkMode = darkModeMediaQuery.matches
10    let isDarkMode = window.localStorage.isDarkMode === 'true' || (!('isDarkMode' in window.localStorage) && isSystemDarkMode)
11
12    if (isDarkMode) {
13      document.documentElement.classList.add('dark')
14    } else {
15      document.documentElement.classList.remove('dark')
16    }
17
18    if (isDarkMode === isSystemDarkMode) {
19      delete window.localStorage.isDarkMode
20    }
21  }
22
23  function disableTransitionsTemporarily() {
24    document.documentElement.classList.add('[&_*]:!transition-none')
25    window.setTimeout(() => {
26      document.documentElement.classList.remove('[&_*]:!transition-none')
27    }, 0)
28  }
29
30  function updateModeWithoutTransitions() {
31    disableTransitionsTemporarily()
32    updateMode()
33  }
34</script>
34<link rel="alternate" type="application/rss+xml" href="undefined/rss/feed.xml"/><link rel="alternate" type="application/feed+json" href="undefined/rss/feed.json"/><link rel="me" href="https://tty0.social/@bketelsen"/><link rel="preload" href="/_next/static/css/56c2344ec8148103.css" as="style"/><link rel="stylesheet" href="/_next/static/css/56c2344ec8148103.css" data-n-g=""/><noscript data-n-css=""></noscript>
34<script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script>
34<script src="/_next/static/chunks/webpack-c4acd79e87956a0e.js" defer=""></script>
34<script src="/_next/static/chunks/framework-7751730b10fa0f74.js" defer=""></script>
34<script src="/_next/static/chunks/main-bf11fce9f4e3622f.js" defer=""></script>
34<script src="/_next/static/chunks/pages/_app-0fac12d0b622de3f.js" defer=""></script>
34<script src="/_next/static/chunks/970-20c4bbbfd2bfc04a.js" defer=""></script>
34<script src="/_next/static/chunks/pages/articles/forecast-cloudy-3682464fc0732b5c.js" defer=""></script>
34<script src="/_next/static/uvWpdkUNmi8lIm869yVZm/_buildManifest.js" defer=""></script>
34<script src="/_next/static/uvWpdkUNmi8lIm869yVZm/_ssgManifest.js" defer=""></script>
34</head><body class="dark:bg-black bg-white">
34<script>
35              (function () {
36                document.documentElement.classList.add('dark');
37                localStorage.setItem('theme', 'dark');
38              })()
39            </script>
39<div id="__next"><div style="visibility:hidden"><div class="sm:px-8 mt-16 lg:mt-32"><div class="mx-auto max-w-7xl lg:px-8"><div class="relative px-4 sm:px-8 lg:px-12"><div class="mx-auto max-w-2xl lg:max-w-5xl"><div class="xl:relative"><div class="mx-auto max-w-2xl"><article><header class="flex flex-col"><h1 class="mt-6 text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">Understanding JavaScript Asynchronous Behavior</h1><time dateTime="2024-06-17" class="order-first flex items-center text-base text-zinc-500 dark:text-zinc-200"><span class="h-4 w-0.5 rounded-full bg-zinc-500 dark:bg-zinc-200"></span><span class="ml-3">June 17, 2024</span></time></header><div class="mt-8 pt-6 prose prose-lg text-xl max-w-none dark:prose-invert  dark:prose-hr:border-zinc-800"><p>JavaScript is single-threaded, but it can handle asynchronous operations efficiently. Let&#x27;s explore how this magic happens.</p><h2>The Event Loop: JavaScript&#x27;s Heart</h2><p>At its core, JavaScript uses an event loop to handle asynchronous operations. Think of it as a traffic controller that manages the flow of code execution.</p><h2>Example.js</h2><pre><code class="code-highlight"><span class="code-line">console.log(&#x27;First&#x27;)
40</span><span class="code-line">setTimeout(() =&gt; console.log(&#x27;Second&#x27;), 0)
41</span><span class="code-line">console.log(&#x27;Third&#x27;)
42</span><span class="code-line">// Output:
43</span><span class="code-line">// First
44</span><span class="code-line">// Third
45</span><span class="code-line">// Second
46</span></code></pre><p>Even with a 0ms timeout, &#x27;Second&#x27; prints last. Why? Because <code>setTimeout</code> is asynchronous!</p><h2>Callbacks: The Traditional Approach</h2><p>Callbacks were the original way to handle asynchronous operations:</p><h2>Example.js</h2><pre><code class="code-highlight"><span class="code-line">function fetchData(callback) {
47</span><span class="code-line">setTimeout(() =&gt; {
48</span><span class="code-line">const data = { id: 1, name: &#x27;Ankit&#x27; }
49</span><span class="code-line">callback(data)
50</span><span class="code-line">}, 1000)
51</span><span class="code-line">}
52</span><span class="code-line">fetchData((data) =&gt; {
53</span><span class="code-line">console.log(data) // Runs after 1 second
54</span><span class="code-line">})
55</span><span class="code-line">
56</span></code></pre><div class="not-prose my-8 flex rounded-3xl p-6 bg-amber-50 dark:bg-slate-800/60 dark:ring-1 dark:ring-slate-300/10"><svg aria-hidden="true" viewBox="0 0 32 32" fill="none" class="flex-none w-8 h-8 [--icon-foreground:theme(colors.amber.900)] [--icon-background:theme(colors.amber.100)]"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id=":R2bl6:-gradient" gradientTransform="rotate(65.924 1.519 20.92) scale(25.7391)"><stop stop-color="#FDE68A" offset=".08"></stop><stop stop-color="#F59E0B" offset=".837"></stop></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id=":R2bl6:-gradient-dark" gradientTransform="matrix(0 24.5 -24.5 0 16 5.5)"><stop stop-color="#FDE68A" offset=".08"></stop><stop stop-color="#F59E0B" offset=".837"></stop></radialGradient></defs><g class="dark:hidden"><circle cx="20" cy="20" r="12" fill="url(#:R2bl6:-gradient)"></circle><path d="M3 16c0 7.18 5.82 13 13 13s13-5.82 13-13S23.18 3 16 3 3 8.82 3 16Z" fill-opacity="0.5" class="fill-[var(--icon-background)] stroke-[color:var(--icon-foreground)]" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="m15.408 16.509-1.04-5.543a1.66 1.66 0 1 1 3.263 0l-1.039 5.543a.602.602 0 0 1-1.184 0Z" class="fill-[var(--icon-foreground)] stroke-[color:var(--icon-foreground)]" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path><path d="M16 23a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z" fill-opacity="0.5" stroke="currentColor" class="fill-[var(--icon-background)] stroke-[color:var(--icon-foreground)]" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path></g><g class="hidden dark:inline"><path fill-rule="evenodd" clip-rule="evenodd" d="M2 16C2 8.268 8.268 2 16 2s14 6.268 14 14-6.268 14-14 14S2 23.732 2 16Zm11.386-4.85a2.66 2.66 0 1 1 5.228 0l
56-1.039 5.543a1.602 1.602 0 0 1-3.15 0l-1.04-5.543ZM16 20a2 2 0 1 0 0 4 2 2 0 0 0 0-4Z" fill="url(#:R2bl6:-gradient-dark)"></path></g></svg><div class="flex-auto ml-4"><p class="m-0 font-display text-xl text-amber-900 dark:text-amber-500">Callback Hell</p><div class="prose mt-2.5 text-amber-800 prose-code:text-amber-900 prose-a:text-amber-900 [--tw-prose-underline:theme(colors.amber.400)] dark:[--tw-prose-underline:theme(colors.sky.700)] [--tw-prose-background:theme(colors.amber.50)] dark:text-slate-300 dark:prose-code:text-slate-300"><p>Nested callbacks can lead to difficult-to-maintain code, often called &quot;callback hell&quot;:</p><div class="remark-code-title">callback-hell.js</div><pre class="language-javascript"><code class="code-highlight language-javascript"><span class="code-line line-number" line="1"><span class="token function">fetchUser</span><span class="token punctuation">(</span><span class="token parameter">user</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
57</span><span class="code-line line-number" line="2">  <span class="token function">fetchProfile</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span><span class="token property-access">id</span><span class="token punctuation">,</span> <span class="token parameter">profile</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
58</span><span class="code-line line-number" line="3">    <span class="token function">fetchPosts</span><span class="token punctuation">(</span>profile<span class="token punctuation">.</span><span class="token property-access">id</span><span class="token punctuation">,</span> <span class="token parameter">posts</span> <span class="token arrow operator">=&gt;</span> <span class="token punctuation">{</span>
59</span><span class="code-line line-number" line="4">      <span class="token comment">// Deep nesting continues...</span>
60</span><span class="code-line line-number" line="5">    <span class="token punctuation">}</span><span class="token punctuation">)</span>
61</span><span class="code-line line-number" line="6">  <span class="token punctuation">}</span><span class="token punctuation">)</span>
62</span><span class="code-line line-number" line="7"><span class="token punctuation">}</span><span class="token punctuation">)</span>
63</span></code></pre></div></div></div><h2>Promises: A Better Way</h2><p>Promises provide a more elegant solution for handling asynchronous operations:</p><p><code>javascript:promise-example.js</code></p><pre><code class="code-highlight"><span class="code-line">function fetchUserData() {
64</span><span class="code-line">return new Promise((resolve, reject) =&gt; {
65</span><span class="code-line">setTimeout(() =&gt; {
66</span><span class="code-line">const user = { id: 1, name: &#x27;Ankit&#x27; }
67</span><span class="code-line">resolve(user)
68</span><span class="code-line">// or if something goes wrong:
69</span><span class="code-line">// reject(new Error(&#x27;Failed to fetch user&#x27;))
70</span><span class="code-line">}, 1000)
71</span><span class="code-line">})
72</span><span class="code-line">}
73</span><span class="code-line">fetchUserData()
74</span><span class="code-line">.then(user =&gt; console.log(user))
75</span><span class="code-line">.catch(error =&gt; console.error(error))
76</span></code></pre><p>Promises can be chained, making the code more readable:</p><p><code>javascript:promise-chain.js</code> <code>showLineNumbers {2-4}</code></p><pre><code class="code-highlight"><span class="code-line">fetchUser()
77</span><span class="code-line">.then(user =&gt; fetchProfile(user.id))
78</span><span class="code-line">.then(profile =&gt; fetchPosts(profile.id))
79</span><span class="code-line">.then(posts =&gt; console.log(posts))
80</span><span class="code-line">.catch(error =&gt; console.error(error))
81</span></code></pre><h2>Async/Await: The Modern Approach</h2><p>Async/await makes asynchronous code look and behave more like synchronous code:</p><p><code>javascript</code> <code>:async-await.js</code> <code>showLineNumbers</code></p><pre><code class="code-highlight"><span class="code-line">async function getUserData() {
82</span><span class="code-line">try {
83</span><span class="code-line">const user = await fetchUser()
84</span><span class="code-line">const profile = await fetchProfile(user.id)
85</span><span class="code-line">const posts = await fetchPosts(profile.id)
86</span><span class="code-line">return posts
87</span><span class="code-line">} catch (error) {
88</span><span class="code-line">console.error(&#x27;Error fetching user data:&#x27;, error)
89</span><span class="code-line">}
90</span><span class="code-line">}
91</span></code></pre><h2>Real-World Example: Fetching API Data</h2><p>Here&#x27;s a practical example combining these concepts:</p><p><code>javascript</code> <code>github-api.js</code></p><pre><code class="code-highlight"><span class="code-line">async function fetchGitHubUser(username) {
92</span><span class="code-line">try {
93</span><span class="code-line">const response = await fetch(https://api.github.com/users/${username})
94</span><span class="code-line">if (!response.ok) {
95</span><span class="code-line">throw new Error(&#x27;User not found&#x27;)
96</span><span class="code-line">}
97</span><span class="code-line">const userData = await response.json()
98</span><span class="code-line">return userData
99</span><span class="code-line">} catch (error) {
100</span><span class="code-line">console.error(&#x27;Error:&#x27;, error.message)
101</span><span class="code-line">throw error
102</span><span class="code-line">}
103</span><span class="code-line">}
104</span><span class="code-line">// Using the function
105</span><span class="code-line">fetchGitHubUser(&#x27;Ankitmohanty2&#x27;)
106</span><span class="code-line">.then(user =&gt;
106 console.log(user))
107</span><span class="code-line">.catch(error =&gt; console.error(error))
108</span></code></pre><h2>Best Practices</h2><ol><li><strong>Always handle errors</strong>: Use try/catch with async/await or .catch() with Promises.</li><li><strong>Avoid mixing patterns</strong>: Stick to either Promises or async/await in a project.</li><li><strong>Use Promise.all() for parallel operations</strong>:</li></ol><p><code>javascript</code> <code>parallel-operations.js</code></p><pre><code class="code-highlight"><span class="code-line">const [users, posts, comments] = await Promise.all([
109</span><span class="code-line">fetchUsers(),
110</span><span class="code-line">fetchPosts(),
111</span><span class="code-line">fetchComments()
112</span><span class="code-line">])
113</span><span class="code-line">
114</span></code></pre><h2>Common Pitfalls to Avoid</h2><ol><li><strong>Not handling rejections</strong>: Always catch potential errors in your async operations.</li><li><strong>Blocking the main thread</strong>: Avoid long-running synchronous operations.</li><li><strong>Sequential vs Parallel</strong>: Know when to use <code>await</code> in sequence vs <code>Promise.all()</code> for parallel execution.</li></ol><p><code>javascript</code> <code>sequential-vs-parallel.js</code></p><pre><code class="code-highlight"><span class="code-line">// Sequential (slower)
115</span><span class="code-line">const userData = await fetchUser()
116</span><span class="code-line">const postData = await fetchPosts()
117</span><span class="code-line">// Parallel (faster)
118</span><span class="code-line">const [userData, postData] = await Promise.all([
119</span><span class="code-line">fetchUser(),
120</span><span class="code-line">fetchPosts()
121</span><span class="code-line">])
122</span><span class="code-line">
123</span></code></pre><h2>Advanced Patterns</h2><h3>Race Conditions</h3><p>Sometimes you need to handle multiple promises but only care about the first one to complete:</p><p><code>javascript</code> <code>race-condition.js</code></p><pre><code class="code-highlight"><span class="code-line">const result = await Promise.race([
124</span><span class="code-line">fetch(&#x27;api1.example.com&#x27;),
125</span><span class="code-line">fetch(&#x27;api2.example.com&#x27;)
126</span><span class="code-line">])
127</span><span class="code-line">
128</span></code></pre><h3>Error Boundaries</h3><p>Creating reusable error handling patterns:</p><p><code>javascript</code> <code>error-boundary.js</code></p><pre><code class="code-highlight"><span class="code-line">async function withErrorHandling(asyncFn) {
129</span><span class="code-line">try {
130</span><span class="code-line">return await asyncFn()
131</span><span class="code-line">} catch (error) {
132</span><span class="code-line">console.error(&#x27;Operation failed:&#x27;, error)
133</span><span class="code-line">// Custom error handling logic
134</span><span class="code-line">throw error
135</span><span class="code-line">}
136</span><span class="code-line">}
137</span><span class="code-line">// Usage
138</span><span class="code-line">const data = await withErrorHandling(async () =&gt; {
139</span><span class="code-line">const response = await fetch(&#x27;/api/data&#x27;)
140</span><span class="code-line">return response.json()
141</span><span class="code-line">})
142</span><span class="code-line">
143</span></code></pre><h2>Conclusion</h2><p>Understanding asynchronous JavaScript is crucial for modern web development. While callbacks served us well, Promises and async/await provide cleaner, more maintainable solutions for handling asynchronous operations.</p><p>Remember: JavaScript&#x27;s asynchronous nature isn&#x27;t about doing multiple things at exactly the same time (it&#x27;s still single-threaded), but about handling operations efficiently without blocking the main thread.</p><h2>References</h2><ul><li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous">MDN Web Docs - Asynchronous JavaScript</a></li><li><a href="https://javascript.info/async">JavaScript.info - Promises, async/await</a></li><li><a href="https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick">Node.js Event Loop Documentation</a></li></ul></div></article></div></div></div></div></div></div></div></div>
143<script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/articles/forecast-cloudy","query":{},"buildId":"uvWpdkUNmi8lIm869yVZm","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script>
143<div style="display:none">        <a rel="me" href="https://tty0.social/@bketelsen">Mastodon</a></div></body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.