<?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: Shaun</title>
    <description>The latest articles on DEV Community by Shaun (@shaunyapp).</description>
    <link>https://dev.to/shaunyapp</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%2Fuser%2Fprofile_image%2F589167%2F6e364c0d-335c-48e3-a11d-3e43270098c7.png</url>
      <title>DEV Community: Shaun</title>
      <link>https://dev.to/shaunyapp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shaunyapp"/>
    <language>en</language>
    <item>
      <title>Executing expensive operations without freezing your UI (or using WebWorkers)</title>
      <dc:creator>Shaun</dc:creator>
      <pubDate>Mon, 07 Feb 2022 17:59:21 +0000</pubDate>
      <link>https://dev.to/shaunyapp/executing-expensive-operations-without-freezing-your-ui-or-using-webworkers-3hp7</link>
      <guid>https://dev.to/shaunyapp/executing-expensive-operations-without-freezing-your-ui-or-using-webworkers-3hp7</guid>
      <description>&lt;h2&gt;
  
  
  What do I need to know?
&lt;/h2&gt;

&lt;p&gt;The concepts that enable this are the event loop and macrotasks. There is also an example of it all working at the end.&lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  The event loop
&lt;/h2&gt;

&lt;p&gt;The event loop is how the JS engine asynchronously executes queued tasks. It monitors the call stack and the task queue. When the call stack is empty it will process the next item on the queue.&lt;/p&gt;

&lt;p&gt;A single loop will involve executing 1 &lt;em&gt;macrotask&lt;/em&gt;, all &lt;em&gt;microtasks&lt;/em&gt; queued during this loop and finally rendering if needed. It then repeats until there are no more tasks and sleeps until a new task is added. It's clear then how a long running macrotask can cause the UI to freeze.&lt;br&gt;
 &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7pJ3YNsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/243wbrvzvrddqh1wbxhn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7pJ3YNsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/243wbrvzvrddqh1wbxhn.png" alt="Event loop diagram" width="356" height="407"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  What is a macrotask (or just task)?
&lt;/h2&gt;

&lt;p&gt;A macrotask is any task waiting for processing on the &lt;em&gt;event loop&lt;/em&gt;. The engine executes these tasks oldest first. Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An event is fired&lt;/li&gt;
&lt;li&gt;When an external script loads&lt;/li&gt;
&lt;li&gt;setTimeout, setInterval, setImmediate etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  And microtasks?
&lt;/h2&gt;

&lt;p&gt;Microtasks are small functions executed after the macrotask is completed, commonly generated as the resolution of a promise or async/await. All microtasks generated during the active loop will run before the next macrotask is executed.&lt;/p&gt;

&lt;p&gt;You can add microtasks directly with &lt;code&gt;queueMicrotask&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;queueMicrotask(() =&amp;gt; {
  // function contents here
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Microtasks can queue other microtasks which can also lead to freezing or even an infinite loop.&lt;br&gt;
 &lt;/p&gt;
&lt;h2&gt;
  
  
  Using this to save your UI
&lt;/h2&gt;

&lt;p&gt;If you need to execute an expensive operation and can batch it, such as iterating over a large array, then macrotasks can enable microtasks and rendering to complete in between. Take the following example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let i = 0;

function count() {
  do {
    i++;
  } while (i % 1e6 != 0); // Process the next million.

  if (i === 1e9) { // We're going to 1 billion.
    console.log('Done!');
  } else {
    setTimeout(count); // Schedule the next batch
  }
}

count();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What the above code is doing is effectively splitting our operation into 1,000 batches, meaning in between each batch the UI can respond to events and update. Rather than being stuck until our long operation completes.&lt;/p&gt;

&lt;p&gt;As events are macrotasks and rendering occurs after the microtasks complete we want to use concepts such as setTimeout rather than queueMicrotask to ensure they are executed between batches.&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  concurrent-each
&lt;/h2&gt;

&lt;p&gt;concurrent-each is a small library I wrote that leverages these concepts to enable expensive array processing while keeping the UI responsive.&lt;/p&gt;

&lt;p&gt;Async array operations to push tasks onto the macrotask queue to prevent UI lock up while processing large volumes of data in batches.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Normal Map&lt;/th&gt;
&lt;th&gt;Concurrent-each Map&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mI9mrUN6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l52302akv0oqdq5qjec8.gif" alt="Normal Map" width="277" height="316"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WKggxllR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6c9w1vpr7viuielux8t.gif" alt="Concurrent-each Map" width="277" height="316"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/Shaun-Y/concurrent-each"&gt;View on GitHub&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/concurrent-each"&gt;View on npmjs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>webdev</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
