{
    "componentChunkName": "component---src-templates-blog-post-tsx",
    "path": "/blog/2021-10-26-effection-async-await/",
    "result": {"data":{"blogPost":{"title":"Effection: for when async/await is not enough","slug":"/blog/2021-10-26-effection-async-await/","authorNodes":[{"name":"Jonas Niklas","slug":"/people/jonas-niklas/"}],"markdown":{"html":"<p>Everyone who has built a complex system in JavaScript has hit a critical moment where the illusion of control comes crashing down. Those are the moments when there are dozens (maybe hundreds) of concurrent processes running and it feels like you've lost control over them. Maybe a promise handler or callback executes even though it is no longer relevant and messes up the state of the system. Or perhaps an error disappears into the void or a socket is not closed when it should be.</p>\n<p>The problem with concurrent processes in JavaScript is that it is fundamentally unstructured. Anyone can add a callback, or await a promise at any time, and once that task is created, it has an <em>unconstrained</em> lifetime. If the async function or the callback is no longer relevant, how do you cancel it? Worse yet, if you're performing multiple callbacks or promises or awaits, are you sure you're dealing correctly with errors in all of them?</p>\n<h2 id=\"introducing-effection\" style=\"position:relative;\"><a href=\"#introducing-effection\" aria-label=\"introducing effection permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introducing Effection</h2>\n<p>The solution is to adopt the ideas of <a href=\"https://vorpus.org/blog/notes-on-structured-concurrency-or-go-statement-considered-harmful/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">structured concurrency</a> and apply them to JavaScript. The core idea of structured concurrency is that the lifetime of a task is always constrained. This means that a task must not outlive its parent, or in other words, it is impossible to create a task that runs <em>forever</em>. This might seem like an obvious constraint, but it is important to note that this is very much <em>not</em> the case with the core concurrency primitives available in JavaScript.</p>\n<p><a href=\"http://frontside.com/effection\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Effection</a> is an Open Source concurrency framework that replaces async/await with a more structured way of writing code. Let's look at how this applies to async/await code:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/users/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>There is nothing special about this async function. And this is what happens when we call this function from another function:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchSomeUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> userOne <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">let</span> userTwo <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">one</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> userOne<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">two</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> userTwo<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Here we're calling <code class=\"language-text\">fetchUser</code> twice, and then awaiting both calls. This will cause both calls to <code class=\"language-text\">fetchUser</code> to execute concurrently. We could also implement this using <code class=\"language-text\">Promise.all</code>, which would behave similarly and is subject to the exact same pitfalls:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchSomeUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> userOne <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">let</span> userTwo <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> Promise<span class=\"token punctuation\">.</span><span class=\"token function\">all</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>userOne<span class=\"token punctuation\">,</span> userTwo<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>It looks like the <code class=\"language-text\">fetchSomeUsers</code> function is nice and self-contained, but in fact it isn't. We start fetching two users, but both of those fetches are in no way tied to the <code class=\"language-text\">fetchSomeUsers</code> function. They run in the background, and no matter what happens within <code class=\"language-text\">fetchSomeUsers</code>, <em>they just keep running</em>. Potentially they could run forever; that's what we mean when we say that their lifetime is unconstrained.</p>\n<p>For example, there is nothing stopping us from doing something silly like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">setTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"I'm still running, lol!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token number\">1000000</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">let</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/users/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">await</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Even ages after the <code class=\"language-text\">fetchUser</code> function has finished, it will still print something to the console. We can't close the existing loopholes (such as <code class=\"language-text\">setTimeout</code>), but as long as you are writing idiomatic Effection code, something like the above just cannot happen.</p>\n<p>Let's look at this example again – but this time using Effection:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> spawn<span class=\"token punctuation\">,</span> fetch <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'effection'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span><span class=\"token operator\">*</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> response <span class=\"token operator\">=</span> <span class=\"token keyword\">yield</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">/users/</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>id<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">yield</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">function</span><span class=\"token operator\">*</span> <span class=\"token function\">fetchSomeUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> userOne <span class=\"token operator\">=</span> <span class=\"token keyword\">yield</span> <span class=\"token function\">spawn</span><span class=\"token punctuation\">(</span><span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">let</span> userTwo <span class=\"token operator\">=</span> <span class=\"token keyword\">yield</span> <span class=\"token function\">spawn</span><span class=\"token punctuation\">(</span><span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">one</span><span class=\"token operator\">:</span> <span class=\"token keyword\">yield</span> userOne<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">two</span><span class=\"token operator\">:</span> <span class=\"token keyword\">yield</span> userTwo<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>It's not that different from before: Effection uses generator functions instead of async functions, and there is something going on with <code class=\"language-text\">spawn</code>, but other than that it looks pretty much the same.</p>\n<p>However, the way that this function runs is very different. When we spawn a task with Effection, its lifetime is tied to the current task, which means that <code class=\"language-text\">fetchUser(1)</code> and <code class=\"language-text\">fetchUser(2)</code> cannot ever outlive fetchSomeUsers. Moreover, no task that <code class=\"language-text\">fetchUser</code> spawns can outlive <code class=\"language-text\">fetchUser</code> either. Effection tasks ensure that everything that happens within the task stays within the task.</p>\n<h2 id=\"using-effection\" style=\"position:relative;\"><a href=\"#using-effection\" aria-label=\"using effection permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Using Effection</h2>\n<p>This might seem like a trivial outcome but the implications are profound. For example, Effection ships with an operation called <code class=\"language-text\">withTimeout</code>, which adds a time limit to any task. If the time limit is exceeded, an error is thrown.</p>\n<p>That means we can now do this:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> withTimeout <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'effection'</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">function</span><span class=\"token operator\">*</span> <span class=\"token function\">fetchSomeUsersWithTimeout</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">yield</span> <span class=\"token function\">withTimeout</span><span class=\"token punctuation\">(</span><span class=\"token number\">2000</span><span class=\"token punctuation\">,</span> <span class=\"token function\">fetchSomeUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Right now in JavaScript something like this is pretty much impossible to implement with promises. There is just no way to know what <code class=\"language-text\">fetchSomeUsers</code> does internally, and there is no way to know whether we really can abort all of it. Trying to write a function like this is at best unsafe and at worst impossible.</p>\n<p>With Effection it all just works. We know that nothing can escape <code class=\"language-text\">fetchSomeUsers</code> and we know that everything that <code class=\"language-text\">fetchSomeUsers</code> does will be canceled if we cancel <code class=\"language-text\">fetchSomeUsers</code> itself.</p>\n<p>Now, imagine that our async/await <code class=\"language-text\">fetchSomeUsers</code> fails for some reason:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token function\">fetchSomeUsers</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> userOne <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">let</span> userTwo <span class=\"token operator\">=</span> <span class=\"token function\">fetchUser</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'boom'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">one</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> userOne<span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">two</span><span class=\"token operator\">:</span> <span class=\"token keyword\">await</span> userTwo<span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>What will happen in this case? <code class=\"language-text\">fetchUser(1)</code> and <code class=\"language-text\">fetchUser(2)</code> will happily keep running, even though the <code class=\"language-text\">fetchSomeUsers</code> function which initially called them has already failed.</p>\n<p><figure class=\"figure\"><img src=\"/img/2021-effection-intro/intro-effection-async-await.svg\"><figcaption class=\"figure-caption\">fetchSomeUsers timing with async/await</figcaption></figure></p>\n<p>This can't happen in Effection. Because given that <code class=\"language-text\">fetchUser(1)</code> and <code class=\"language-text\">fetchUser(2)</code> are scoped to their parent function, they will be terminated when <code class=\"language-text\">fetchSomeUsers</code> enters into an error state.</p>\n<p><figure class=\"figure\"><img src=\"/img/2021-effection-intro/intro-effection-effection.svg\"><figcaption class=\"figure-caption\">fetchSomeUsers timing with effection</figcaption></figure></p>\n<p>And this is the power of Effection's structured concurrency: it allows us to build abstractions that would otherwise be impossible to construct. We think it is a fundamentally better way to write JavaScript.</p>\n<h3 id=\"going-further\" style=\"position:relative;\"><a href=\"#going-further\" aria-label=\"going further permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Going further</h3>\n<p>There is much more to Effection than what we've shown here. Effection is not only a framework that allows you to write rock-solid code, but it also gives you amazing insights into your application through our experimental <a href=\"http://frontside.com/effection/docs/guides/inspector\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">inspector</a>. If you're curious to learn more, this <a href=\"http://frontside.com/effection/docs/guides/introduction\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">guide</a> explains in greater detail how to use Effection, and the <a href=\"https://frontside.com/effection/api/index.html\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">API Reference</a> contains a complete reference of all methods and types that Effection provides.</p>\n<p>We are a small but dedicated team at Frontside that likes to tackle challenging problems with an ambitious solution. There is boundless work to be done, and boundless ideas to explore. Do you want to join us on this journey? Come hang out with us <a href=\"https://discord.gg/Ug5nWH8\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">on discord</a>, where we stream our work and are always interested in discussing where to go next.</p>","frontmatter":{"date":"October 26, 2021","description":"Everyone who has built a complex system in JavaScript has hit a critical moment when concurrent processes become unmanageable. But with Effection—an OSS async/await alternative—you'll spare memory leaks and headaches. ","tags":["dx","javascript"],"img":{"childImageSharp":{"fixed":{"src":"/static/c588855a2e02779b29504f163481ca0a/31987/2021-intro-effection.png"}}}}}}},"pageContext":{"id":"fc0c6e59-0f9c-56c5-8f44-9b37f8694a59"}},
    "staticQueryHashes": ["1241260443"]}