<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Ari on Medium]]></title>
        <description><![CDATA[Stories by Ari on Medium]]></description>
        <link>https://medium.com/@Arii_?source=rss-aea3addf5661------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>Stories by Ari on Medium</title>
            <link>https://medium.com/@Arii_?source=rss-aea3addf5661------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 27 May 2026 20:39:23 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@Arii_/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Thoughts on JavaScript Thunks]]></title>
            <link>https://medium.com/better-programming/thoughts-on-javascript-thunks-fa25e38fb55?source=rss-aea3addf5661------2</link>
            <guid isPermaLink="false">https://medium.com/p/fa25e38fb55</guid>
            <category><![CDATA[thunk]]></category>
            <category><![CDATA[callback]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[event-loop]]></category>
            <dc:creator><![CDATA[Ari]]></dc:creator>
            <pubDate>Thu, 26 Sep 2019 18:18:41 GMT</pubDate>
            <atom:updated>2019-09-30T07:53:32.552Z</atom:updated>
            <content:encoded><![CDATA[<h4>How does JavaScript deal with asynchronous concurrent behavior?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*m3ktmJe3jOu0bpZfXmDL_g.png" /></figure><p>JavaScript is a single-threaded synchronous language, yet dealing with asynchronous behavior is a huge part of development. How can we as web developers create a truly interactive and dynamic user experience if we don’t consider:</p><ul><li>How we’re handling functionality where values in one function depend on the execution of values from a prior function</li><li>The problems each asynchronous pattern presents</li><li>Whether there’s a better tool for the instant</li></ul><p>How does JavaScript deal with asynchronous concurrent behavior (multiple tasks happening within the same time frame)? There are a handful of patterns that exist to handle concurrency within the language, but which is the best tool for the job? <em>Thunks</em> exist as a means to manage concurrency. How do we use them and what do they bring to the table?</p><h3>What Are Thunks?</h3><p>Thunks are a pattern used to handle asynchronous behavior, represented as a variation of a callback function. To understand why using thunks as a pattern is necessary, I’m going to first take you down a small rabbit hole covering one of the asynchronous programming problems callbacks functions are trying to solve — the ability to reason about asynchronous logic.</p><h4><strong>How does JavaScript handle asynchronous behavior?</strong></h4><p>The <em>event loop</em> is a model that JavaScript employs in order to prioritize how the evaluation of tasks are processed back into the thread of execution, composed of a <em>call stack</em>, <em>microtask</em>, and <em>callback queue</em>. While this can be a complex thing to explain, here is a real-world example of how these different pieces work together using the event loop.</p><p>Let’s use an airport boarding process. There are three tiers of tickets, each with a corresponding line: the first, second, and third tiers are reserved for call stack, microtask, and callback ticket holders, respectively. There is a single pathway onto the plane: through the line reserved for call stack ticket holders. The flight attendant announces the plane is ready to board, and everyone with a call stack ticket has priority. Once all call stack ticket holders have boarded, everyone holding a microtask ticket is asked to step into the call stack line to enter the plane. Once completed, those holding a callback ticket are asked to do the same. The flight attendant looks a little nervous as the call stack ticket holders are entering the plane — a few people are missing and she continues to check the microtask line. Alas! There were a few microtask ticket holders who arrived late. She halts the callback ticket holders boarding, processes the microtask ticket holders and allows them to use the call stack line to board the plane before resuming the boarding of the remaining callback ticket holders. Once all ticket holders have boarded, the door closes and the plane lifts off.</p><p>Perhaps that example is a bit contrived. However, this is a high-level example of a concurrent model based on the event loop, where JavaScript’s runtime environment ensures a nonblocking I/O by coordinating responses from tasks executed within a certain time frame, to give the perception of multiple tasks being performed at once (in parallel).</p><p>Now you may be asking:</p><ul><li>How do we manage the output of these concurrent responses?</li><li>How does the way we manage our concurrent responses scale as the complexity of those responses increase?</li></ul><h4><strong>Callbacks</strong></h4><p>The most common solution to managing concurrency is callbacks; functions that take an extra argument, a callback function. The execution of the initial function initiates some asynchronous operation and its return value is used in the execution of the callback.</p><pre>const request = require(&#39;request&#39;);</pre><pre>const asyncWork = request(&#39;someAsyncWork&#39;, (err, response) =&gt; {<em> <br>  // Handle error<br>  // On success, handle results<br></em>});</pre><p>There are a couple of issues that come to a head when using callbacks. <em>Inversion of control</em> and reasoning about the code as it becomes more complex are the two that I’m aware of. Inversion of control is where we implicitly trust third-party utilities to use our callbacks in the way we’ve intended, which clearly won’t always happen. But that’s a topic for another post.</p><p>As we begin to introduce new asynchronous dependencies to our application — the execution of a callback which depends on the return value of a prior asynchronous call — reasoning about what each piece of code is doing becomes increasingly difficult because callbacks express the execution of asynchronous dependencies by nesting.</p><p>An issue that comes into play with nesting callbacks is how we handle scope. Local variables are only in context within the body of the function they’re declared in. Variables move out of context as functions are called within other functions, and move back into scope as functions return. In considering how to deal with scope to manage concurrent requests, a couple of factors to be considered are time and persisting state.</p><ul><li>How do we handle out-of-scope variables and asynchronous dependencies?</li><li>How do we persist the data?</li></ul><pre>const request = require(&#39;request&#39;);</pre><pre>const asyncWork = (&#39;someAsyncWork&#39;, (err, resOne)=&gt; {<br>  if (err) {<br>    <em>//Handle Error <br>  </em>} else {<br>    request(`someMoreAsyncWork/${resOne}`, (err, resTwo)=&gt; {<br>      if (err) {<br>        <em>//Handle error <br>      </em>} else {<br>        request(`andMoreAsyncWork/${resTwo}`, (err, resThree)=&gt; {<br>              if (err) {<br>                <em>//Handle error<br>              </em>} else {<br>                 <em>//Notice the horror yet?<br>              </em>}<br>            });<br>          }<br>        });<br>      }<br>    });</pre><pre><em>//But wait! What if I not only needed the values returned to do other asynchronous work, but also to build some data.</em></pre><pre><em>//insert work here</em></pre><pre><em>const cache = //...</em></pre><p>We need a way to express asynchronous code so it can be reasoned about more easily. An evolution of the callback pattern is… thunks.</p><h3><strong>Thunks</strong></h3><p>A thunk is a container around some state. Synchronous thunks take no parameters and contain state by making use of closure — it’s a function that returns a function, thus has access to some private state via its lexical environment (closed over variable environment) even when the function is being executed outside of the lexical scope.</p><pre>const func = () =&gt; {<br>  <em>//Can instantiate some variable here<br>  </em>return () =&gt; {<br>    <em>//Access to closed over variable environment<br>    </em>console.log(&#39;This is a thunk&#39;);<br>  };<br>};</pre><pre>const thunk = func();<br>const result = thunk();</pre><p><em>Asynchronous thunks</em> are very similar to synchronous thunks. The key difference being that asynchronous thunks take a callback value as a parameter. By defining asynchronous functions in this manner we’re able to:</p><ul><li>Delay some functionality until a later time</li><li>Use the state made available by the closed-over variable environment</li></ul><pre>const request = require(&#39;request&#39;);</pre><pre>const func = asyncVariable =&gt; {<br>  let input;<br>  const cache = {};<br>  request(`someAsyncWork/${asyncVariable}`, (err, res) =&gt; {<br>    <em>//Handle Error<br>    </em>input = res;<br>  });<br>  return cb =&gt; {<br>    const results = cb(input);<br>    <em>//Use the cache available in closed over variable environment to      build results<br>  </em>return cache;<br>  };<br>};</pre><pre>const thunk = func(&#39;someInput&#39;);<br>const cachedResult = thunk(cb);</pre><p>In using thunks to manage concurrency we’re able to take advantage of the lexical environment created by using closure and create an encapsulation to persist state and compose values together. Our code also becomes slightly more easy to reason about and less clunky.</p><h3><strong>Conclusion</strong></h3><p>Thunks aren’t the end-all answer. They’re a step in the direction of a better tool for managing concurrency as applications become increasingly complex. Yet, there remain problems that callbacks create and thunks don’t solve, such as inversion of control. But who knows? As we generate more complex solutions, there most likely is a promise of a better way to manage concurrency.</p><h3><strong>Resources</strong></h3><ul><li>Will Sentance, “JavaScript The Hard Parts: Async &amp; Promises”</li><li>Kyle Simpson, “Rethinking Asynchronous JavaScript”</li></ul><p>Thanks for reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fa25e38fb55" width="1" height="1" alt=""><hr><p><a href="https://medium.com/better-programming/thoughts-on-javascript-thunks-fa25e38fb55">Thoughts on JavaScript Thunks</a> was originally published in <a href="https://betterprogramming.pub">Better Programming</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>