<?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: Alexander Nenashev</title>
    <description>The latest articles on DEV Community by Alexander Nenashev (@alexander-nenashev).</description>
    <link>https://dev.to/alexander-nenashev</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%2F911056%2F3b0e9f74-4b5d-4adc-affd-cb01b512af15.jpg</url>
      <title>DEV Community: Alexander Nenashev</title>
      <link>https://dev.to/alexander-nenashev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alexander-nenashev"/>
    <language>en</language>
    <item>
      <title>Myopia, Exotropia, and Code: Developing a Vision Training Tool for Near-Sighted Professionals</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Tue, 03 Mar 2026 14:41:00 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/myopia-exotropia-and-code-developing-a-vision-training-tool-for-near-sighted-professionals-5bh0</link>
      <guid>https://dev.to/alexander-nenashev/myopia-exotropia-and-code-developing-a-vision-training-tool-for-near-sighted-professionals-5bh0</guid>
      <description>&lt;p&gt;Target audience: people whose work is mostly near-sight (developers, etc.), with myopia or other eye focusing–related problems, or those willing to keep their vision sharp regardless of near-sight work strain.&lt;/p&gt;

&lt;p&gt;Disclaimer: the following text does not make any medical claims; it only assumes the existing possibility of improving vision with eye muscle exercises.&lt;/p&gt;

&lt;p&gt;Being myopic (-4.5d), in 2023 I started doing simple eye exercises for 5–10 minutes before falling asleep. Since then, my vision improved to some degree, which I considered worth sharing, so I created a YouTube channel in Russian to share my experience. By that time, due to regular exercises, I had acquired pretty good eye muscle sensitivity, so I could feel which eye muscles contract and relax, given that I had learned &lt;a href="https://en.wikipedia.org/wiki/Extraocular_muscles" rel="noopener noreferrer"&gt;eye muscle anatomy&lt;/a&gt; in detail. This allowed me to develop my own precise view of what causes myopia. This is a logical continuation of the &lt;a href="https://en.wikipedia.org/wiki/Bates_method" rel="noopener noreferrer"&gt;Bates method&lt;/a&gt;. Regardless of the mainstream consensus that it is false, the main idea—that coarse focusing is done by extraocular muscles and final focusing by the eye lens—allowed many people who shared their experiences with me to get rid of myopia and other eye focusing problems. I even read a 2018 article in an ophthalmological journal claiming that the Bates theory is not entirely without merit and that further studies should be conducted on the matter (unfortunately, I cannot find it now).&lt;/p&gt;

&lt;p&gt;My experience suggested that myopia happens due to shortening of the eye &lt;a href="https://en.wikipedia.org/wiki/Extraocular_muscles" rel="noopener noreferrer"&gt;rectus muscles&lt;/a&gt;, especially the medial ones (internal, near the nose), which converge the eyes for near focusing. In July 2025, I began stereo reading—reading text in two columns in parallel view—where the eyes diverge to the point of exotropia, a state in which the eyes diverge beyond parallel alignment. I also found that my myopic audience has very poor ability to diverge and achieve any significant exotropia, whereas people without myopia have strong exotropia ability. Since then, exotropia and stereo reading have become my main tools for training my eyes. Reading alone is used in many vision improvement systems, including Bates’.&lt;/p&gt;

&lt;p&gt;So I started in June 2025 being able to read (in non-stereo mode, just regular text) 2 mm lowercase letters from a 33-centimeter distance and ended on December 31 being able to read 7 mm lowercase letters from a 3-meter distance. That was a 2.6× improvement in angular letter size, which also corresponded to significant improvement in my everyday vision. Since then, I have been convinced that eye muscle exercises can be a working tool to mitigate eye focusing problems such as myopia.&lt;/p&gt;

&lt;p&gt;In June 2025, I started the &lt;a href="https://stereoreader.github.io/app/" rel="noopener noreferrer"&gt;Stereo Reader web app&lt;/a&gt; as my tool for stereo reading. Vue/TypeScript/PWA were selected for the implementation. What seemed like an easy project soon became a challenge.&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%2Fmkrncwlj3t22iujnlhz0.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%2Fmkrncwlj3t22iujnlhz0.jpg" alt="Home screen" width="800" height="359"&gt;&lt;/a&gt;&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%2Fjsv1hzwflk1c44pnmu3b.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%2Fjsv1hzwflk1c44pnmu3b.jpg" alt="Reading mode" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After I shared the app with my eye training audience, it became clear that support for many e-book formats was required, including those with large amounts of text. Moreover, when adjusting reading settings such as font size, gap between text columns, and the span of the reading area, the currently visible text on the screen should not be lost.&lt;/p&gt;

&lt;p&gt;So I developed a simple semantic system where any text document format is split into paragraphs (called “chunks” for brevity), each with its own font style, with lines calculated dynamically character by character based on the text column width. Since I had spent a lot of time &lt;a href="https://stackoverflow.com/search?tab=votes&amp;amp;q=user%3a14098260%20benchmark&amp;amp;searchOn=3" rel="noopener noreferrer"&gt;benchmarking&lt;/a&gt; JavaScript and &lt;a href="https://dev.to/alexander-nenashev/series/27389"&gt;avoiding any extra string/array allocation&lt;/a&gt;, I achieved fairly fast text layout calculation. However, it still takes 300–400 ms to process a huge novel like Asimov’s &lt;em&gt;Forward the Foundation&lt;/em&gt; (about 140,000 words) on mid-range mobile devices (I tested on Snapdragon 720G). The issue is that layout recalculation occurs on any setting change that affects text column width. In any case, the UX is acceptable.&lt;/p&gt;

&lt;p&gt;Having the text layout available, I implemented virtual scrolling while maintaining the full text container’s real height. This allows the text to appear as if it were loaded into a single DOM element with scrolling. Further improvements could include rethinking how users interact with partial scrolling and using Web Workers to process text in parallel.&lt;/p&gt;

&lt;p&gt;Further work included adding stereo image viewing and introducing games, such as a moving ball to train exotropia in motion, and so on.&lt;/p&gt;

&lt;p&gt;In any case, this project seems to have become my ongoing lifelong journey, and I welcome anyone to join.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stereoreader.github.io" rel="noopener noreferrer"&gt;The website&lt;/a&gt; will include documentation on usage, the application can be tried &lt;a href="https://stereoreader.github.io/app/#try" rel="noopener noreferrer"&gt;here&lt;/a&gt;. You can also join its &lt;a href="https://www.youtube.com/channel/UCbRfdGzQ0Lwm87MthvMfcyw" rel="noopener noreferrer"&gt;YouTube channel&lt;/a&gt; and &lt;a href="https://t.me/stereoreader" rel="noopener noreferrer"&gt;Telegram channel&lt;/a&gt; for future tutorials and news, and ask any questions in the &lt;a href="https://t.me/stereoreader_chat" rel="noopener noreferrer"&gt;community&lt;/a&gt; or via &lt;a href="https://t.me/alexoran" rel="noopener noreferrer"&gt;telegram&lt;/a&gt; or &lt;a href="mailto:aleks4hour@gmail.com"&gt;email&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Avoid intermediate arrays (parsing strings) to make you Javascript fast</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Sat, 18 May 2024 16:42:30 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/avoid-intermediate-arrays-parsing-strings-to-make-you-javascript-fast-5beg</link>
      <guid>https://dev.to/alexander-nenashev/avoid-intermediate-arrays-parsing-strings-to-make-you-javascript-fast-5beg</guid>
      <description>&lt;p&gt;In the previous post there was argued why we should &lt;a href="https://dev.to/alexander-nenashev/avoid-intermediate-arrays-in-js-5bkg"&gt;avoid intermediate arrays&lt;/a&gt; for performance in cases like filter/map chains.&lt;/p&gt;

&lt;p&gt;I'd say &lt;code&gt;String#split()&lt;/code&gt; is heavily overused when parsing strings. A common scenario is to get the first word in a string. The first thought is to split a string into words and get the first one. Again, an intermediate array is created, worse, only the first element is used, the rest is just waste of space and time. Use &lt;code&gt;String#indexOf()&lt;/code&gt; and &lt;code&gt;String#slice()&lt;/code&gt; instead:&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;$length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&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;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark Array#split&lt;/span&gt;
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&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="c1"&gt;// @benchmark String#indexOf&lt;/span&gt;
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&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="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark regex&lt;/span&gt;
&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;match&lt;/span&gt;&lt;span class="p"&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="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="s2"&gt;` Chrome/125
-----------------------------------------------------------------------------------------------
&amp;gt;                       n=1        |       n=10        |       n=100       |       n=1000      
String#indexOf   ■ 1.00x x100m 972 | ■ 1.00x x100m 959 | ■ 1.00x  x10m  94 |  ■ 1.00x x100m 967
regex              2.99x  x10m 291 |   3.06x  x10m 293 |   3.07x  x10m 289 |    2.96x  x10m 286
Array#split        6.49x  x10m 631 |  22.52x   x1m 216 | 165.96x x100k 156 | 1509.82x  x10k 146
----------------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;span class="s2"&gt;` Firefox/126
------------------------------------------------------------------------------------------------
&amp;gt;                       n=1        |       n=10        |       n=100       |       n=1000       
String#indexOf   ■ 1.00x x100m 105 | ■ 1.00x x100m 120 | ■ 1.00x x100m 108 |   ■ 1.00x x100m 109
regex             35.90x  x10m 377 |  27.83x  x10m 334 |  33.15x  x10m 358 |    32.11x  x10m 350
Array#split       39.05x  x10m 410 | 105.00x   x1m 126 | 944.44x x100k 102 | 10000.00x  x10k 109
------------------------------------------------------------------------------------------------ `&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://silentmantra.github.io/benchmark#H4sIAAAAAAAACm2Oyw6CMBBFf2WCJpRAeGwxGP0CFyytJlgGqEIx7SwwhH8XC3HFbiZzzr0zOqIv0UmdFgn2LaqaGsggOXAlemUIDOl5P2tdfMJK9x0bFyj90z4kUwDMg%2BwILqEh1wufvVTMBdebc7iKIjg9UImmK%2FRrydqZdyuJzw06tKOlr%2FFtQ8hJS1XvpCpxuFSr00qBLA5%2B%2F4XrxUZsNWqscVi8riDRsOjOee5Hts%2BZvsWGsk8EAQAA"&gt;Open in the playground&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Pre-allocate arrays to make Javascript fast</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Sat, 18 May 2024 14:05:11 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/always-pre-allocate-arrays-in-javascript-pfc</link>
      <guid>https://dev.to/alexander-nenashev/always-pre-allocate-arrays-in-javascript-pfc</guid>
      <description>&lt;p&gt;If you ever implemented a dynamic array in low level languages like C++ you allocate a chunk of memory for several elements at once, when there's no more space for new elements you allocate a new chunk. I guess this is valid and for Javascript arrays. Allocation of a memory on the heap is an expensive operation. &lt;/p&gt;

&lt;p&gt;Let's try in Chrome's console (several times, the output is the most frequent):&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;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&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;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&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="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;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&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="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;heap allocated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;);&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;heap&lt;/span&gt; &lt;span class="nx"&gt;allocated&lt;/span&gt; &lt;span class="mi"&gt;1688&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&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;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;_000_000&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="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;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;performance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;usedJSHeapSize&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="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;heap allocated&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;);&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="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;heap&lt;/span&gt; &lt;span class="nx"&gt;allocated&lt;/span&gt; &lt;span class="mi"&gt;4001684&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we see with 1_000_000 array length we have 3.8Mb allocated.&lt;/p&gt;

&lt;p&gt;Of course the reason behind the optimization could be different or composite, I'm not a developer of any current JS engines, but it seems that changing the length of an array is generally an expensive operation.&lt;/p&gt;

&lt;p&gt;Regardless of the actual JS implementation if we follow the rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the final size of an array is known during creation of the array - allocate it:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&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;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knownSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This immediately boosts your Javascript speed:&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;$length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&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;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;$length&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark non pre-allocated&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="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;result&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="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&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="c1"&gt;// @benchmark pre-allocated&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="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;}&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="c1"&gt;// @benchmark Array#map&lt;/span&gt;
&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="s2"&gt;` Chrome/125
-----------------------------------------------------------------------------------------------
&amp;gt;                         n=10       |      n=100       |      n=1000       |      n=10000     
pre-allocated       ■ 1.00x x10m  85 | ■ 1.00x x10m 669 | ■ 1.00x   x1m 474 | ■ 1.00x x100k 560
Array#map             1.69x x10m 144 |   1.79x  x1m 120 |   2.15x x100k 102 |   3.20x  x10k 179
non pre-allocated     3.22x x10m 274 |   3.57x  x1m 239 |   4.11x x100k 195 |   3.66x  x10k 205
----------------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;span class="s2"&gt;` Firefox/126
---------------------------------------------------------------------------------------------
&amp;gt;                         n=10       |      n=100      |      n=1000       |     n=10000     
pre-allocated       ■ 1.00x x10m 227 | ■ 1.00x x1m 162 | ■ 1.00x x100k 192 | ■ 1.00x x10k 208
non pre-allocated     1.44x x10m 327 |   1.45x x1m 235 |   1.16x x100k 222 |   1.53x x10k 319
Array#map             1.46x x10m 332 |   1.06x x1m 172 |   1.73x x100k 333 |   2.17x x10k 452
--------------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://silentmantra.github.io/benchmark#H4sIAAAAAAAACp2QwU7DMBBEf2UUerDVNi3XGiP4jjhCJnWJhbOONu4BRfl35LiIA5eKyx52Z2fe7lx18eyqUxVcwiY4%2Bkg9NB6PylAXaUqwzNB4ZbZf9YXjIOaiOv3Ilx3E2w5eQj%2FDS2XI0OGAl3dHXT9Y%2FgRFwshub0OInU3ubGg2BJQAdtM1JGg0rcrdS2SRaTw0jgoeT5mhLmEKfruV6zZum%2FV4nXphmRvfytVhyaUMlaHlL9AdMOvB4jdY%2Fout8S00Ctt9aGvuw2BHQ9l5sKPwt8dWyzfk7DtsrgEAAA%3D%3D"&gt;Open in the playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keep in mind though that you create a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections#sparse_arrays"&gt;sparse array&lt;/a&gt; with &lt;code&gt;Array(size)&lt;/code&gt; so some methods like &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;forEach()&lt;/code&gt; wouldn't work as expected, but the iterators works fine like &lt;code&gt;[...arr]&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Avoid iterators/generators to make Javascript fast</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Fri, 17 May 2024 12:09:43 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/avoid-iteratorsgenerators-in-javascript-116n</link>
      <guid>https://dev.to/alexander-nenashev/avoid-iteratorsgenerators-in-javascript-116n</guid>
      <description>&lt;p&gt;If we look at the iterator protocol we'd notice it comes at a cost of creating &lt;code&gt;{value, done}&lt;/code&gt; objects, accessing their props, and calls of &lt;code&gt;next()&lt;/code&gt; (a function call is generally is an expensive operation). &lt;/p&gt;

&lt;p&gt;Given all the hurdles we have a quite inefficient tool to iterate our data. Moreover when we implement an iterator with a generator we suddenly notice that performance got even worse. I guess that's because of the cost of keeping a generator's scope and its state between calls.&lt;/p&gt;

&lt;p&gt;Don't get me wrong, iterators and generators are good abstractions, &lt;code&gt;for await&lt;/code&gt; is exceptionally amazing when dealing with async data and abstracting backend API calls, so generally used in business logic they bring benefits but when we descend into the realm of transforming data, generic data handling functions and algorithms we should care to avoid them when possible.&lt;/p&gt;

&lt;p&gt;Here's a benchmark of several ways to iterate an array and you see  the iterator and generator fail considerably. I'm not the only one complaining, I've seen several comments that generators' speed keeps people from using them widely.&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;Iter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&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="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&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;i&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;const&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&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="na"&gt;done&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iter&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="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="p"&gt;]:&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;iter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&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="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&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;else&lt;/span&gt; &lt;span class="nx"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;out&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="nx"&gt;iter&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;i&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;$input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$input&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;iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Iter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark generator&lt;/span&gt;
&lt;span class="k"&gt;for&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;e&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark iterator&lt;/span&gt;
&lt;span class="k"&gt;for&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;e&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark for..of&lt;/span&gt;
&lt;span class="k"&gt;for&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;e&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark for&lt;/span&gt;
&lt;span class="k"&gt;for&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;i&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;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark forEach&lt;/span&gt;
&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

&lt;span class="s2"&gt;` Chrome/125
-----------------------------------------------------------------------------------------
&amp;gt;                 n=10        |       n=100       |      n=1000       |      n=10000     
for           1.17x x100m 336 |   1.20x  x10m 354 |   1.01x   x1m 235 | ■ 1.00x x100k 218
for..of       1.19x x100m 340 |   1.21x  x10m 355 | ■ 1.00x   x1m 232 |   1.00x x100k 219
forEach     ■ 1.00x x100m 286 | ■ 1.00x  x10m 294 |   1.00x   x1m 233 |   4.54x  x10k  99
iterator     64.34x   x1m 184 |  13.71x   x1m 403 |  10.86x x100k 252 |  10.96x  x10k 239
generator    43.01x   x1m 123 |  36.05x x100k 106 |  45.69x  x10k 106 |  43.58x   x1k  95
----------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;span class="s2"&gt;` Firefox/126
-----------------------------------------------------------------------------------------
&amp;gt;                 n=10        |       n=100       |      n=1000       |      n=10000     
for         ■ 1.00x x100m 512 | ■ 1.00x  x10m 505 | ■ 1.00x   x1m 453 | ■ 1.00x x100k 449
forEach       1.62x x100m 828 |   1.48x  x10m 746 |   4.26x x100k 193 |   6.57x  x10k 295
for..of      11.07x  x10m 567 |   9.35x   x1m 472 |   9.98x x100k 452 |  10.11x  x10k 454
iterator     23.44x   x1m 120 |  10.93x   x1m 552 |  11.24x x100k 509 |  10.71x  x10k 481
generator    82.62x   x1m 423 |  64.75x x100k 327 |  66.67x  x10k 302 |  68.37x   x1k 307
----------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://silentmantra.github.io/benchmark#H4sIAAAAAAAACoVSwW6jMBD9ladoD7BBtHuFddUeetjzHkNUuWRIrDrjamLajSL%2BvbINNNUi9QKaN%2B8Nbx5zWbVuR6tq1Vp9OuGPJ8GlYeDnnjjTInkqgc4JMkseBgq3NQx%2BQ4uUlnjvDzXMej1zgbMhuwv9jdnWCRzCKz6MJ%2Fky%2B3NsqlvHJw%2FXeyhc8KZtTxW4t7bAzjFV6LQ9EYYv9DA18CcLm7%2Fn47OzZcC1d7KtkOVQd5FYTCymf35qzFLAdMgMlFJXO%2BbBURkMQMFLT0UEoj2o6K%2F%2BnEDB4XU%2FhrFeb684Qr4XDqwZHMawRmBkBMv1mN%2FQcMNp5R%2FtoecXqNH%2Fg4g%2Bl524Y3ZJliv8uh0KZE8FTNo9r2ex4deY8GZbBHNQIzQzxkSZ3uNh1OHDNze4fyZuD0ctL9gTp3Ab7pxkSUZwXdSW0w3lC9Lptywr5xNZknZOytJ1%2FykDf5meqN9d73yuCxMedXtoOEjGIqN4MkNer4YP3LYJCEYDAAA%3D"&gt;Open in the playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One would argue that &lt;code&gt;for..of&lt;/code&gt; in Chrome performs nice despite of using an array's iterator but that's an optimization of using a native iterator. Firefox is generally more honest in benchmarks if we want generic evaluation of Javascript code, but about that is in the next post.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Avoid intermediate arrays (filter/map) to make Javascript fast</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Wed, 15 May 2024 08:21:51 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/avoid-intermediate-arrays-in-js-5bkg</link>
      <guid>https://dev.to/alexander-nenashev/avoid-intermediate-arrays-in-js-5bkg</guid>
      <description>&lt;p&gt;If you aim to write fast Javascript avoid intermediate arrays when transforming data or making an algorithm. This could happen both with imperative and functional code. Always ask yourself a question while writing code - are there any intermediate arrays I could avoid.&lt;/p&gt;

&lt;p&gt;Often I see a common pattern &lt;code&gt;filter + map&lt;/code&gt;:&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;arr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;num&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="nx"&gt;arr&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes the chain is quite long, hosting several filter/map/sort in various configurations.&lt;/p&gt;

&lt;p&gt;Replace the chain with &lt;code&gt;Array#reduce()&lt;/code&gt; which in mostly all cases will give you better performance over any chain of other methods, since you remove the array created by &lt;code&gt;Array#filter()&lt;/code&gt;:&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="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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="nx"&gt;n&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;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;r&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="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/tracygjg"&gt;@tracygjg&lt;/a&gt; asked in a comment why not to use:&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="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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="nx"&gt;n&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;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="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;Thank &lt;a class="mentioned-user" href="https://dev.to/tracygjg"&gt;@tracygjg&lt;/a&gt; for this one, that's another great example where you create an intermediate array, moreover an array is created for every element in the result array! &lt;/p&gt;

&lt;p&gt;So basically each time we want to add an element to the result, a bigger array is created thus the bigger the source array the slower the solution.&lt;/p&gt;

&lt;p&gt;Moreover the spread syntax is used which should be avoided too if you want a performant solution (my next post is about that). Let's benchmark all the 3 options:&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;$chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&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="na"&gt;num&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;$input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; 

&lt;span class="c1"&gt;// @benchmark filter + map&lt;/span&gt;
&lt;span class="nx"&gt;$input&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;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// @benchmark reduce&lt;/span&gt;
&lt;span class="nx"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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="nx"&gt;n&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;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;r&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="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="c1"&gt;// @benchmark Tracy Gilmore&lt;/span&gt;
&lt;span class="nx"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&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="nx"&gt;n&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;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&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="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

&lt;span class="s2"&gt;` Chrome/124
-------------------------------------------------------------------------------------------
&amp;gt;                     n=10       |       n=100       |      n=1000       |     n=10000     
reduce          ■ 1.00x x10m 355 | ■ 1.00x   x1m 155 | ■ 1.00x x100k 263 | ■ 1.00x x10k 431
filter + map      1.88x x10m 669 |   1.74x   x1m 269 |   1.41x x100k 370 |   1.55x  x1k  67
Tracy Gilmore     3.32x  x1m 118 |  20.13x x100k 312 | 196.20x   x1k 516 | 893.27x  x10 385
------------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;span class="s2"&gt;` Firefox/126
-------------------------------------------------------------------------------------------
&amp;gt;                     n=10       |       n=100       |      n=1000       |     n=10000     
reduce          ■ 1.00x x10m 647 | ■ 1.00x   x1m 433 | ■ 1.00x x100k 390 | ■ 1.00x x10k 470
filter + map      1.41x  x1m  91 |   1.27x x100k  55 |   2.51x  x10k  98 |   1.32x x10k 620
Tracy Gilmore     1.90x  x1m 123 |   9.70x  x10k  42 | 175.64x   x1k 685 | 359.57x  x10 169
------------------------------------------------------------------------------------------- `&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://silentmantra.github.io/benchmark#H4sIAAAAAAAACn3OMU%2FDMBCG4b%2FyKUKVDZELSCyp0paJiY0tyWAcF0eNL9HVHqoo%2Fx1FBlohxOi70%2FN6yszQ2qzIzECngBvjIh1R4plZn9WBBy%2Bm3tJHcAUe7uccQqLcQkwUfYFXHZxiTe3ghZyl3NT05XQ0xoASVbNBTTWt19i%2FWzLOaz7i0PXBMu7g9VhTOlZpKGjxSVH02EI9SeX1eD28xePS%2BU2ybaOxP1h6CsE5KP34QmK1Aqsxnpy4kDlY5qiav%2Bw31uaMl673A%2F%2BTuCrsUCmlls13oEEBToFs%2FgTMS4rRdgEAAA%3D%3D"&gt;Open in the playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see with 10000 array items we could have a hundreds of times slower solution if we don't care enough about avoiding intermediate arrays.&lt;/p&gt;

&lt;p&gt;In the next post we will discuss how to avoid intermediate arrays while &lt;a href="https://dev.to/alexander-nenashev/avoid-intermediate-arrays-parsing-strings-to-make-you-javascript-fast-5beg"&gt;parsing strings&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>performance</category>
      <category>webdev</category>
      <category>ux</category>
    </item>
    <item>
      <title>Every millisecond matters in Javascript</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Tue, 14 May 2024 11:05:51 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/every-millisecond-matters-in-javascript-13ab</link>
      <guid>https://dev.to/alexander-nenashev/every-millisecond-matters-in-javascript-13ab</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Premature optimization is the root of all evil -- Donald Knuth&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In light of modern trends of increasing complexity of modern JS frameworks, high end developer hardware and the premature optimization mantra we ended up with some performance problems with modern web and especially modern mobile web (deserves a separate article). &lt;/p&gt;

&lt;p&gt;Probably you can't comfortably use modern web sites on a 5 year old mid/low budget device, at least the most people don't expect to upgrade their PCs used just for web surfing every year. I've ended up buying a high end android phone just to use social sites comfortably. &lt;/p&gt;

&lt;p&gt;One could tell that a user couldn't tell a difference between 1 and 5 ms, but given the fact we could have hundreds of operations on page or data loading, all these small overheads lead to a noticeable performance hit and poor user experience.&lt;/p&gt;

&lt;p&gt;So I'd say that every millisecond matters in Javascript. Premature optimization is bad when you spend significant amount of time on a code piece that is thrown away later due refactoring. But what if you could write highly performant Javascript code from the beginning? You just don't need to optimize later and the whole premature optimization thing isn't relevant anymore. So learn how to write fast Javascript, I believe it will pay off.&lt;/p&gt;

&lt;p&gt;In the next posts that would form a series I will be collecting tips how to write fast Javascript.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ux</category>
      <category>performance</category>
    </item>
    <item>
      <title>Conditional wrap component in Vue 3 pt.3</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Fri, 10 May 2024 17:09:41 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/conditional-wrap-component-in-vue-3-pt3-8dp</link>
      <guid>https://dev.to/alexander-nenashev/conditional-wrap-component-in-vue-3-pt3-8dp</guid>
      <description>&lt;p&gt;Previously we observed 2 options to create a conditional wrap component in Vue 3. Now it's time for the most complex one which exploits vnodes in a deeper way.&lt;/p&gt;

&lt;p&gt;On the client side it's pretty ordinary with the wrapper provided in a &lt;code&gt;wrapper&lt;/code&gt; slot and the wrapped content in the default one. But we do some magic inside the wrap component:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We collect all leaf vnodes in the wrapper slot's vnode tree&lt;/li&gt;
&lt;li&gt;We inject our content into the leaves like they'd support a default slot. For that we should set &lt;code&gt;shapeFlag&lt;/code&gt; of the leaves as &lt;code&gt;ShapeFlags.ARRAY_CHILDREN | ShapeFlags.ELEMENT&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://play.vuejs.org/#eNp9VG1v2zYQ/is39UNswKbWrdgC1WmSdh6WIcuKNGhRVEVBS5TERiIJknJcuP7vPb5ItoO238i7547PPby7bXKpFFn3LMmShSk0VxYMs716kQtFNROWlLLoO3ew3LYMzuDknaZKMQ0P3DZgWmnNyfNc5IJ3SmoLW9CsmkEDO6i07OAE0ztAdLvo6CCpu4TgQgpjgZuQvMR3MMukoq1hUw9YpIEfMsOLZZ1qqWV4A1g8uJwZN3N3wGhvRfuAgifBoaMDXSVfQ9FSY87yJDrzZHQ/AnAhmI7JHWyRonef6+C2SI+YocFJGXBXJx1EggM4OBepM4fjqrdWCrgoWl7cu6cPFPllvCCHO1nX+B+R1CINgZjkiAJejf2COFPIIAyJEVv33IoW97WWvSjnhWylzuDJKa1QbwBFy5KLOoOnf6iNt6ykLhlCnqoNGNnyEmpNvxy45pqWvDcZPIsRHdU1FxmcYsSv3826Q0JH6v6IVlWd/igBdoYrEWtLZonFQkXFa/LZSIFd7fPlSSE7xVum/1eWY6flSQbe43y0beXDv95mdc9mg71oWHH/Hftns3G2PHmtmWF6zfJk9FmsmNngXr65YRs8j85Oln2L6J84bxkq2zuOAfYSNUDaBzjP9srPEupwZ5Yby4QZinJEHXLn8XmCs/fqJ6Xv6f5Onvk4VBRVdG2GCqJ+41C/aahif7e0NsNg58kFpk9Ng4sCO3I/4lscHCnY2xtZshGLUI8ZRr3iorxmdM0MdvZkLRA7g2I1hbMX4Jh4Cyka3pa4h85Jy0SN++bcOx+7SSX1khZNyONS7NMf5J4CaurDi1UwT3PhObGNZ16yivYtkutF4dTy22qyHeduN4Ot33i7KWroUvEKJvu5nOLWsr0WYS2SmG4SNhi+6iuPnY5lB1S8T6akw8fGCvYaRqouCxwWth3Kz4acyG+Mj58chMJPCr+Hr+5/klze3l6+//Tqn6vrv26XN/D10Le8Xv63vLnzj0L8oVFwOD8/gw8fp0T1ppkQQh4VHLjuhsKjKpFlGNtc+C5TWirXAtv98s/gpZQtowJ2zwG7MbTVHNV5NNXBcdzSRz3pRqixVpksTXuh7muCiyA9gFxg35Pf/sQNbmw0EWa6+SrMHb6XJ+Nc7L4BjTFsmA=="&gt;See on Vue SFC Playground&lt;/a&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ShapeFlags&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="s2"&gt;@vue/shared&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;cloneVNode&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="s2"&gt;vue&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;findLeaves&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&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;vnode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; 
    &lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;findLeaves&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="nf"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;isWrapped&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slots&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;isWrapped&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;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;cloneVNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nf"&gt;findLeaves&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;vnode&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;vnode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shapeFlag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ShapeFlags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRAY_CHILDREN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;ShapeFlags&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="o"&gt;??=&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="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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;wrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isWrapped&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;wrap&lt;/span&gt; &lt;span class="na"&gt;:is-wrapped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;#wrapper&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"inner-wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
      I'm wrapped
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/wrap&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see the DX is pretty good, with full ability to define our wrapper with any nesting fully inside a template. &lt;/p&gt;

&lt;p&gt;Now you have a choice to select a wrap component from 3 options or probably combine them into one ultimate component.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Conditional wrap component in Vue 3 pt.2</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Fri, 10 May 2024 14:14:32 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/conditional-wrap-component-in-vue-3-pt2-aco</link>
      <guid>https://dev.to/alexander-nenashev/conditional-wrap-component-in-vue-3-pt2-aco</guid>
      <description>&lt;p&gt;In the previous post we create a pretty idiomatic component that would work well for simple cases. Let's explore more options. What can be done to present our wrapper as a template as more DX friendly? Of course we could compile it runtime, but for a simple 1 level wrapper we could use the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.vuejs.org/#eNp9U01v2zAM/SucdkgCJPaKFUPhpt3WoYcO2AfWArv4okiyq0aWBElOXRj+76Vk5+NQ9EbxPZKPFNmT79Zmu1aQgqw9c9IG8CK09rrUljqhQ8YNa5toBBmUgCuY3cvGovXsqLXCzS5LXWp0GRegBycqGKBypoEZ5o3ohP1H/gRkeXyMkcxoH0D66LGCYwFMMa+o8mKRCOt8FIaS8BEEFqdB4AtgHTVAIf1qFMOTF/1c7oAp6v1VSSadJZlAhGN7owlwN2umVvgBz/eEdY6ZxlJ5JI3mpg3BaPjGlGRbrHAq/sPhgQUfTF0fJ7XOx0BMss5P+sCnDy/I88yMPWRTRB/LbSjb1s60mq+YUcYV8PGCVjgaAEs5l7ou4OyL7ZJnYxwXSDmzHXijJIfa0ZcTaOUol60v4HyKaKirpS7gAiM+oWdIE496UAhZkoCqdCXr7MkbjWuSNJWEmcZKJdwfGyT+YEkKSEjEqFLm+WfyBdeK5d7PHgXbvuF/8l30leSvE164nSjJAQsoT4QRvr3/LTq0D2BjeKuQ/Q74T+AY2qhxpN3gHFH2CS+pvUs7irN88LddENrvm4pCI3NI/JLgTv94p/Wj3M/ZeYrDieIU407gBHF+okvXwEVFWxWgajWLadJ5zPvD9gxL6L0ywQ+LlNzhVTp9vJOvMJZMnGzKNl8A9viWP6tw2X5hhZ02HK/4GpKRsUepON55PDWUWuok1DpjPS5zf6xXwI0xSlANwyUZXgFQ72xE"&gt;See on Vue SFC Playground&lt;/a&gt;&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;isWrapped&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slots&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;isWrapped&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; 
    &lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;flatMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vnode&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;vnode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isWrapped&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;wrap&lt;/span&gt; &lt;span class="na"&gt;:is-wrapped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        I'm wrapped
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/wrap&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it looks non idiomatic, also it generates the wrapper's vnode every time even it's discarded, but it was an interesting case to explore for better DX.&lt;/p&gt;

&lt;p&gt;In the next post we'll explore a more idiomatic option with using 2 slots for the content and wrapper.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Conditional wrap component in Vue 3</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Fri, 10 May 2024 08:45:37 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/creating-a-conditional-wrap-component-in-vue-3-18ml</link>
      <guid>https://dev.to/alexander-nenashev/creating-a-conditional-wrap-component-in-vue-3-18ml</guid>
      <description>&lt;p&gt;Often it's needed to wrap some part of a template in a wrapper &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for example. It seems easy using &lt;code&gt;v-if&lt;/code&gt; but we have a duplication we'd like to avoid:&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;div&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"isWrapped"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- some big chunk of markup --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;template&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- the same big chunk --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's explore our options how we can solve this task without the duplication. Let's call our component &lt;code&gt;&amp;lt;wrap&amp;gt;&lt;/code&gt; and our component that wraps the content a wrapper. Our wrap component is stateless so let's make it functional.&lt;/p&gt;

&lt;p&gt;Our first option would be simple. We support a wrapper component and its props:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.vuejs.org/#eNp9U8tu2zAQ/JUtC0Q24EgNGhSBIveJHNJDWzQBeqh6oClKZiyRBEk5Cgz9e5cU/WhQ5Lacmd0dLpc78knrdNtzkpPCMiO0A8tdr9+XUlPDpUsrxfrOB064lsMSkjvRaYweDdWam+S6lKVESBkHOzC8hhFqozpIsK5nI/cL9ZFIM3+YMpmS1oGwHtG8wgZYYlbT1vJ5EBTZZAwt4cFxbE4dxxNA4T1AHp0sS3Isc3YGSSW2SUmAtdRaJKOsJCEXs/0tfQBwm3TxPlXksoksMg9P4ap3Tkn4yFrBNv80W8KrwwHL36umOQ6oyKZELFJkJ/bxaN0T6ixTmIdIGjN2vt2Ksk1jVC+rc6ZaZXJ4fUVrnAiAplUlZJPDxTs9BGSlTMVRcqEHsKoVFTSGPp1Q54ZWorc5XMaMjppGyByuMOMNImMYtPeDRsiCOHQla9GkD1ZJ3I7gqSRMdVq03HzXTuDDlSSHwHiOtq16/BowZ3q+2ONszdnmP/iDHTxWkh+GW262vCQHzqE97ib65u4bHzA+kJ2q+hbVL5A/OY6h9x4n2WecI9o+0QW3t2E1cZb39mZwXNr9pbxRrxyDviS4yl9euPrR7tv0MuThRHGKfidwgji/wwdZP/8efAhMxWvatw7qXjLfIPyX2S6uxLiAnW2Vswugzhk7zkNvg3/VyP2mwQdYz2IcdQsIWWmsPpvPIX8OTa9fymBWG6UtLvTvZP+//1yT8S+HH2nF"&gt;See on Vue SFC Playground&lt;/a&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;h&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrs&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;wrapper&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Wrap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&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;wrapper&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Usage:&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;wrap&lt;/span&gt; &lt;span class="na"&gt;:wrapper=&lt;/span&gt;&lt;span class="s"&gt;"isWrapped &amp;amp;&amp;amp; 'div'"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"wrapper"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
      I'm wrapped
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/wrap&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is pretty sufficient, you can use any wrapper component with a default slot. But a problem here is that for more complex cases like having multiple nested wrappers we should define the wrapper outside our markup since having a functional wrapper component inside &lt;code&gt;:wrapper&lt;/code&gt; property looks pretty messy. In the next posts of this series we'll explore other options of defining our conditional wrap component.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>frontend</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Memoized getters in ES6 classes</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Tue, 23 Apr 2024 12:21:58 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/memoized-getters-in-es6-data-classes-of5</link>
      <guid>https://dev.to/alexander-nenashev/memoized-getters-in-es6-data-classes-of5</guid>
      <description>&lt;p&gt;We've already seen that &lt;a href="https://dev.to/silentmantra/enhance-your-backend-data-with-es6-classes-20l3"&gt;attaching prototypes&lt;/a&gt; could greatly enhance our data, for example we could add a lot of derived data with getters. The problem is that some of calculated properties could be costly and in most cases we'd want to cache them since usually backend data is pretty static, we update it with POSTing to a backend. &lt;/p&gt;

&lt;p&gt;Thanks to class inheritance we can provide a base class for our data classes and add any class or/and instance utilities we need:&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;BaseObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nf"&gt;defineCachedGetters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getters&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for &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;name&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;getters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&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;prototype&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;get&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;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getters&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="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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&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;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                        &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;configurable&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="na"&gt;writable&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="nx"&gt;options&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;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;configurable&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineCachedGetters&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nf"&gt;discounts&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;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="cm"&gt;/*  
            here we do some expensive calculations and transformations, 
            the result is an array of the user's discounts
        */&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;out&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;Here we cache a getter's result in an own property of an instance. We make it non enumerable since derived data shouldn't be potentially serialized in a state (&lt;code&gt;JSON.stringify&lt;/code&gt;). Later we can delete the property to allow the getter to be evaluated again.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>es6</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Enhance your backend data with ES6 classes</title>
      <dc:creator>Alexander Nenashev</dc:creator>
      <pubDate>Mon, 22 Apr 2024 13:48:34 +0000</pubDate>
      <link>https://dev.to/alexander-nenashev/enhance-your-backend-data-with-es6-classes-20l3</link>
      <guid>https://dev.to/alexander-nenashev/enhance-your-backend-data-with-es6-classes-20l3</guid>
      <description>&lt;p&gt;A traditional way of handling backend data on a frontend is to feed it to services, controllers, components and the like. But when I started binding ES6 classes to backend data and all business logic went into classes, my components got much cleaner, and I got a lot of possibilities to handle and transform data inside classes. It was a big shift to make my frontend code cleaner and shorter. You just simply use &lt;code&gt;Object.setPrototypeOf&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;classes.mjs&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;fullName&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;firstName&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;lastName&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;User&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;./classes.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// fetch some users then attach the class&lt;/span&gt;
&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setPrototypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;User&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="c1"&gt;// now you can use `user.fullName` anywhere&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another reason to bind class prototypes is performance. You don't need to create a new copy of data consisting of class instances, copy data into instance properties and so on and thus you save precious CPU time and memory providing faster user experience.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>frontend</category>
      <category>es6</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
