<?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: Bogdan</title>
    <description>The latest articles on DEV Community by Bogdan (@bgdnandrew).</description>
    <link>https://dev.to/bgdnandrew</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%2F2568752%2Fe9ae4634-7d37-4b61-9ee7-f22c49c1a685.jpg</url>
      <title>DEV Community: Bogdan</title>
      <link>https://dev.to/bgdnandrew</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bgdnandrew"/>
    <language>en</language>
    <item>
      <title>The Self-Hosting Rabbit Hole</title>
      <dc:creator>Bogdan</dc:creator>
      <pubDate>Fri, 11 Apr 2025 21:13:22 +0000</pubDate>
      <link>https://dev.to/bgdnandrew/the-self-hosting-rabbit-hole-1p9o</link>
      <guid>https://dev.to/bgdnandrew/the-self-hosting-rabbit-hole-1p9o</guid>
      <description>&lt;p&gt;Trading convenience for over-optimization is a sin that has killed the momentum of many projects. But if you lower the stakes and package this swap as a learning opportunity, it suddenly becomes excusable, even encouraged.&lt;/p&gt;

&lt;p&gt;Until recently, I was a paying customer of a cloud-hosted analytics platform built on an open-source core. Then I turned to Coolify, a PaaS (Platform as a Service) for managing self-hosted codebases, to try running that same open-source version myself. In fact, I was so excited to finally try out Coolify, I was actually looking forward to the DevOps headaches I was inevitably about to run into.&lt;/p&gt;

&lt;p&gt;I already had servers up in production, and my Plausible Analytics bill was getting expensive. However, the convenience of the low-hanging fruit or cost-cutting played no major role here. The possibility of introducing a significant improvement to my usual deployment workflow was the real catalyst.&lt;/p&gt;

&lt;p&gt;If you're already familiar with platforms like Heroku or Vercel, you know that you're paying for the convenience of running your code on AWS's infrastructure without dealing with AWS's complexity. These platforms "wrap" the power of the Amazon's cloud, and serve it to their customers in a streamlined form. This is more convenient for someone with no DevOps experience, and people are often willing to pay a premium for convenience.&lt;/p&gt;

&lt;p&gt;Think of Coolify as a similar abstraction layer - it simplifies the process of managing your own server, removing much of the manual configuration.&lt;/p&gt;

&lt;p&gt;Without Coolify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you need to manually ssh into your server&lt;/li&gt;
&lt;li&gt;configure Nginx&lt;/li&gt;
&lt;li&gt;use docker compose to orchestrate your database, backend, frontend, etc.&lt;/li&gt;
&lt;li&gt;need a to deploy the latest version of your applictaion? you need to ssh again and pull the latest updates from your remote.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Coolify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you access your server via a web interface&lt;/li&gt;
&lt;li&gt;you link it to your own GitHub account&lt;/li&gt;
&lt;li&gt;select the repos Coolify should have access to&lt;/li&gt;
&lt;li&gt;every push to the main/ master branch will trigger a new production deployment; no need to ssh into your server and clone the latest version of your repository&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Is life without Coolify really that bad? No, not at all. It's like driving a car with manual transmission. If you're a real car buff, you might actually like it better. I know I do.&lt;/p&gt;

&lt;p&gt;Additionally, too much abstraction can take the fun away. In the right scenario, abstraction makes processes more efficient. A human will never be able to shift gears as fast as an automatic transmission, and I will need to take just a bit longer to deploy my apps without something like Coolify.&lt;/p&gt;



&lt;h2&gt;
  
  
  How to start self-hosting
&lt;/h2&gt;

&lt;p&gt;I use servers with dedicated vCPUs from &lt;a href="https://hetzner.cloud/?ref=1iiHIqE0r44K" rel="noopener noreferrer"&gt;Hetzner&lt;/a&gt;. You can get a VPS capable of running production applications, for $20/mo ($15 for the server + $5 for the automatic backups). The costs are capped (better said, fixed), so you won't have any unpleasant surprises when you get the monthly bill.&lt;/p&gt;

&lt;p&gt;I initially installed Coolify on an existing VPS that already had a few manually configured containers. This made setting up Coolify more complicated than it had to be. Simply running &lt;code&gt;docker-compose down&lt;/code&gt; wasn’t enough to avoid conflicts. Because of this, I highly recommend installing Coolify on a fresh server.&lt;/p&gt;

&lt;p&gt;In fact, the most time-consuming problem I faced could have been avoided if I had started with a clean server. After completing the setup, I ran into an issue where Coolify was running properly, but the server itself was inaccessible from localhost.&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%2Fbgdnandrew.com%2F_next%2Fimage%3Furl%3D%252F_next%252Fstatic%252Fmedia%252Fthe-self-hosting-rabbit-hole-1.f326cf79.jpg%26w%3D3840%26q%3D75" 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%2Fbgdnandrew.com%2F_next%2Fimage%3Furl%3D%252F_next%252Fstatic%252Fmedia%252Fthe-self-hosting-rabbit-hole-1.f326cf79.jpg%26w%3D3840%26q%3D75" alt="Coolify Dashboard" width="1038" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I only discovered the real cause a few days later when I tried assigning custom subdomains. The issue? Coolify’s built-in proxy (Traefik) was being blocked by Nginx, which was still running from my previous container setup.&lt;/p&gt;

&lt;p&gt;The issue in question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Server is not reachable. Reason: root@host.docker.internal: Permission denied &lt;span class="o"&gt;(&lt;/span&gt;publickey&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a step by step guide that walks you through installing Coolify, check out my &lt;a href="https://github.com/bgdnandrew/bgdnandrew-DevOps" rel="noopener noreferrer"&gt;DevOps repository&lt;/a&gt;.&lt;/p&gt;



&lt;h2&gt;
  
  
  Why add another layer of complexity?
&lt;/h2&gt;

&lt;p&gt;Vendor lock-in is always a risk. When a platform controls both your tooling and your infrastructure, they can raise prices overnight, and there’s not much you can do about it. That’s what happened with Heroku in 2022. Heroku was my go-to place for launching my Django projects. Additionally, Heroku was an important platform for researchers and hobbyists. 6 years ago, every cool Computer Vision project I was seeing on Twitter was hosted on Heroku.&lt;/p&gt;

&lt;p&gt;Unfortunatelly, Vercel followed a similar path in 2023. Crazy pricing changes. This was even more concerning. Since Vercel makes Next.js, it’s no surprise that deploying Next.js apps over there is a smooth experience. But what happens when you want to leave?&lt;/p&gt;

&lt;p&gt;People talk as if hosting Next.js outside Vercel is some huge ordeal, but in my experience, it’s been surprisingly easy. I kept seeing posts on Twitter/X about how difficult it was, so I expected a mess. Instead, I found that with a bit of configuration, it works just fine on a basic VPS. It’s not quite as plug-and-play as Vercel, but it’s nowhere near the nightmare people make it out to be.&lt;/p&gt;

&lt;p&gt;That said, I still have projects hosted on Vercel. I’m not their biggest fan, but I respect the fact that they at least offer a free tier for early-stage projects. If they ever get rid of that though, I imagine we’ll see history repeat itself.&lt;/p&gt;



&lt;h2&gt;
  
  
  Further down the rabbit hole
&lt;/h2&gt;

&lt;p&gt;I was already comfortable running my own code on my own infrastructure. By hosting Plausible myself, I was joining a growing trend in tech—people running their own instances of open-source software: sometimes to learn, sometimes to save money, sometimes just for the fun of it.&lt;/p&gt;

&lt;p&gt;When you build something yourself, you know exactly how it works. If something breaks, you can usually guess why. But running someone else’s code is different. It comes with its own assumptions, constraints, and quirks that you have to figure out as you go.&lt;/p&gt;

&lt;p&gt;There was a time when the Coolify team offered Plausible as a 1-click install, but due to a dispute, this option is not longer available. With that said, Plausible is still an easy deployment. But I couldn't resist looking deeper into its inner workings.&lt;/p&gt;

&lt;p&gt;One interesting discovery was Plausible's data storage approach: PostgreSQL for transactions and ClickHouse for OLAP. I'd worked with analytical databases in ML pipelines before, where query speed on large datasets matters. Seeing these two types of databases working together in a production system showed me how they complement each other in practice.&lt;/p&gt;

&lt;p&gt;Figuring this process out was so much fun, I already have my eye out for other prospective self-hosted candidates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Why would anyone pay for Plausible's hosted version when they could just run it themselves?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I believe it is for the same reason people use Heroku or Vercel instead of raw AWS (which is already an abstraction in itself). Sure, you don't technically need them, but AWS is for professionals, it is complex. Regular people value simplicity.&lt;/p&gt;

&lt;p&gt;Plausible works the same way. The community edition is free, but running it yourself means handling servers, maintenance, and updates. If you choose their cloud version, you don't have to worry about any of that.&lt;/p&gt;

&lt;p&gt;Additionally, they have employed a really smart tactic. To create a protective barrier for their paid version, they only update the open-source release twice a year. This way, they can claim that their Plausible is "cutting edge" and the Community Edition is "stable".&lt;/p&gt;

&lt;p&gt;This is a dream scenario for them. Since they've reached a critical mass of users, and an even more impressive fanbase, the open source community builds their product, while they focus on keeping the business viable. Lesson learned. I am actually applying this to one of my own projects.&lt;/p&gt;

&lt;p&gt;Self-hosting is a great learning experience. But at the end of the day, the real question is: are you in the right position to trade convenience for optimization?&lt;/p&gt;



&lt;p&gt;&lt;a href="https://bgdnandrew.com" rel="noopener noreferrer"&gt;Bogdan Andrei&lt;/a&gt;, April 2025&lt;/p&gt;

</description>
      <category>devops</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Gap That LeetCode's 30 Days of JavaScript Actually Fills</title>
      <dc:creator>Bogdan</dc:creator>
      <pubDate>Sat, 14 Dec 2024 23:51:19 +0000</pubDate>
      <link>https://dev.to/bgdnandrew/the-gap-that-leetcodes-30-days-of-javascript-actually-fills-38ep</link>
      <guid>https://dev.to/bgdnandrew/the-gap-that-leetcodes-30-days-of-javascript-actually-fills-38ep</guid>
      <description>&lt;p&gt;Most coding challenges teach you to solve puzzles. &lt;a href="https://leetcode.com/studyplan/30-days-of-javascript/" rel="noopener noreferrer"&gt;LeetCode's 30 Days of JavaScript&lt;/a&gt; study plan does something different: it shows you how puzzle pieces can transform into bricks, ready to build real-world projects.&lt;/p&gt;

&lt;p&gt;This distinction matters. When you solve a typical algorithmic problem, you're training your mind to think abstractly. But when you implement a debounced&lt;sup id="fnref1"&gt;1&lt;/sup&gt; function or build an event emitter&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, you're learning how real software works.&lt;/p&gt;

&lt;p&gt;I discovered this while working through the challenges myself. The experience was less like solving brain teasers and more like archaeology - uncovering specific, modern JavaScript concepts. Each section focused on another piece of JS's modern features.&lt;/p&gt;

&lt;p&gt;The peculiar thing about this study plan is that it won't teach you JavaScript. In fact, I believe you need to already know JavaScript reasonably well to benefit from it. What it teaches instead is how JavaScript is actually used to solve real engineering problems.&lt;/p&gt;

&lt;p&gt;Consider the Memoize&lt;sup id="fnref3"&gt;3&lt;/sup&gt; challenge. On the surface, it's about caching function results. But what you're really learning is why libraries like React need memoization to handle component rendering efficiently. Or take the Debounce&lt;sup id="fnref1"&gt;1&lt;/sup&gt; problem - it's not just about implementing delays; it helps you understand, firsthand, why every modern frontend framework, elevator, and basically any system with an interactive UI, need this pattern.&lt;/p&gt;

&lt;p&gt;This focus on practical patterns rather than language basics creates an interesting constraint; you need to be in one of two positions to benefit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You understand CS fundamentals (especially Data Structures and Algorithms) and are comfortable with JavaScript&lt;/li&gt;
&lt;li&gt;You're strong in CS theory and have some prior JavaScript exposure&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bridging CS and Software Engineering
&lt;/h2&gt;

&lt;p&gt;Something odd happens between learning computer science and practicing software engineering. The transition feels like learning chess theory for years, only to find yourself playing a different game entirely - one where the rules keep changing and most moves aren't in any book.&lt;/p&gt;

&lt;p&gt;In CS, you learn how a binary tree works. In software engineering, you spend hours debugging your API, trying to understand why the response caching isn't working. From a distance, the overlap between these worlds might seem significantly bigger than it actually is. There is a gap there, and it can often shock CS graduates when they start their careers. Unfortunately, most educational resources fail to bridge it. They either stay purely theoretical ("here's how quicksort works") or purely practical ("here's how to deploy a React app").&lt;/p&gt;

&lt;p&gt;What makes this JavaScript study plan interesting isn't that it's particularly well-designed - it's that it creates connections between these worlds. Take the memoization problem: &lt;strong&gt;2623. Memoize&lt;/strong&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. In CS terms, it's about caching computed values. But implementing it forces you to grapple with JavaScript's peculiarities around object references, function contexts, and memory management. Suddenly, &lt;br&gt;
you're not just learning an algorithm - you're starting to understand why something like &lt;a href="https://redis.io" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; exists.&lt;/p&gt;

&lt;p&gt;This style repeats throughout the challenges. The Event Emitter&lt;sup id="fnref2"&gt;2&lt;/sup&gt; implementation isn't just about a textbook observer pattern - you can look at it as the reason why taking the V8 engine out of the browser, and building Node.js around it, actually made sense. The Promise Pool&lt;sup id="fnref4"&gt;4&lt;/sup&gt; tackles parallel execution, a.k.a., the reason why your database needs connection limiting.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Hidden Curriculum
&lt;/h2&gt;

&lt;p&gt;The sequence of problems in this study plan isn't random. It's building a mental model of modern JavaScript, layer by layer.&lt;/p&gt;

&lt;p&gt;It starts with closures. Not because closures are the simplest concept - they're notoriously confusing - but because they're foundational to how JavaScript manages state.&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;function&lt;/span&gt; &lt;span class="nf"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;init&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&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;count&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCounter&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="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="nf"&gt;counter1&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 10&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="nf"&gt;counter1&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 11&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="nf"&gt;counter1&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 12&lt;/span&gt;

&lt;span class="c1"&gt;// const counter1 = createCounter(10);&lt;/span&gt;
&lt;span class="c1"&gt;// when this^ line executes:&lt;/span&gt;
&lt;span class="c1"&gt;// - createCounter(10) creates a new execution context&lt;/span&gt;
&lt;span class="c1"&gt;// - local variable count is initialized to 10&lt;/span&gt;
&lt;span class="c1"&gt;// - a new function is created and returned&lt;/span&gt;
&lt;span class="c1"&gt;// - this returned function maintains access &lt;/span&gt;
&lt;span class="c1"&gt;// to the count variable in its outer scope&lt;/span&gt;
&lt;span class="c1"&gt;// - this entire bundle &lt;/span&gt;
&lt;span class="c1"&gt;// (function (the inner one) + its access to count) &lt;/span&gt;
&lt;span class="c1"&gt;// is what we call a closure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This pattern is the seed of all state management in JavaScript. Once you understand how this counter works, you understand how React's useState works under the hood. You grasp why module patterns emerged in pre-ES6 JavaScript.&lt;/p&gt;

&lt;p&gt;Then the plan moves to function transformations. These teach you function decoration - where functions wrap other functions to modify their behavior. This isn't just a technical trick; it's how Express middlewares work, how React higher-order components operate, &lt;br&gt;
and also how TypeScript decorators work.&lt;/p&gt;

&lt;p&gt;By the time you reach the asynchronous challenges, you're not just learning about Promises - you're discovering why JavaScript needed them in the first place. The Promise Pool&lt;sup id="fnref4"&gt;4&lt;/sup&gt; problem isn't teaching you an innovative, quirky JS concept; it's showing you why connection pooling exists in every database engine.&lt;/p&gt;

&lt;p&gt;Here's a rough mapping of the study plan's sections to real-world software engineering concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closures&lt;/strong&gt; → State Management&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Basic Array Transformations&lt;/strong&gt; → Basic skill (auxiliary); Practical Example: Data Manipulation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function Transformations&lt;/strong&gt; → Middleware Patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Promises and Time&lt;/strong&gt; -&amp;gt; Async Control Flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt; -&amp;gt; Basic skill (auxiliary); Practical Example: Data Serialization, API Communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classes&lt;/strong&gt; (especially in the context of Event Emitters) → Message Passing Systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bonus&lt;/strong&gt; (Premium Locked) -&amp;gt; Mix of harder challenges that could've been included in the sections mentioned above; Promise Pool&lt;sup id="fnref4"&gt;4&lt;/sup&gt; is my favourite one from this section&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Pattern Recognition, Not Problem Solving
&lt;/h2&gt;

&lt;p&gt;Let's dissect some problems that showcase this study plan's real value. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Memoize&lt;/strong&gt; (#2623)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consider the Memoize challenge. What I love about it, is the fact that the best solution (that I was able to come up with)&lt;br&gt;
is so straightforward, it's as if the code itself is gently telling you what it does (still, I included some comments).&lt;/p&gt;

&lt;p&gt;This doesn't make #2623 an easy problem, by any means. I needed 2 previous iterations to make it this clean:&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="cm"&gt;/**
 * @param {Function} fn
 * @return {Function}
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Create a Map to store our results&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&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;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create a key from the arguments&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// If we've seen these arguments before, return cached result&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;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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;cache&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Otherwise, calculate result and store it&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="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&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="k"&gt;return&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedFn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;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="s2"&gt;computing...&lt;/span&gt;&lt;span class="dl"&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;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&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="nf"&gt;memoizedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// logs "computing..." and returns 5&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="nf"&gt;memoizedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// just returns 5, no calculation&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="nf"&gt;memoizedFn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// logs "computing..." and returns 7&lt;/span&gt;


&lt;span class="c1"&gt;// Explanantion:&lt;/span&gt;
&lt;span class="c1"&gt;// It's as if our code had access to an external database&lt;/span&gt;

&lt;span class="c1"&gt;// Cache creation&lt;/span&gt;
&lt;span class="c1"&gt;// const cache = new Map();&lt;/span&gt;
&lt;span class="c1"&gt;// - this^ uses a closure to maintain the cache between function calls&lt;/span&gt;
&lt;span class="c1"&gt;// - Map is perfect for key-value storage&lt;/span&gt;

&lt;span class="c1"&gt;// Key creation&lt;/span&gt;
&lt;span class="c1"&gt;// const key = JSON.stringify(args);&lt;/span&gt;
&lt;span class="c1"&gt;// - this^ converts arguments array into a string&lt;/span&gt;
&lt;span class="c1"&gt;// - [1,2] becomes "[1,2]"&lt;/span&gt;
&lt;span class="c1"&gt;// - we are now able to use the arguments as a Map key&lt;/span&gt;

&lt;span class="c1"&gt;// Cache check&lt;/span&gt;
&lt;span class="c1"&gt;// if (cache.has(key)) {&lt;/span&gt;
&lt;span class="c1"&gt;//     return cache.get(key);&lt;/span&gt;
&lt;span class="c1"&gt;// }&lt;/span&gt;
&lt;span class="c1"&gt;// - if we've seen these arguments before, return cached result;&lt;/span&gt;
&lt;span class="c1"&gt;// no need to recalculate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Debounce&lt;/strong&gt; (#2627)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Imagine you're in an elevator, and there's a person frantically pressing the "close door" button repeatedly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;press&lt;/em&gt; &lt;em&gt;press&lt;/em&gt; &lt;em&gt;press&lt;/em&gt; &lt;em&gt;press&lt;/em&gt; &lt;em&gt;press&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Without debouncing: The elevator would try to close the door at every single press, making the door mechanism work inefficiently and possibly break.&lt;/p&gt;

&lt;p&gt;With debouncing: The elevator waits until the person has stopped pressing for a certain time (let's say 0.5 seconds) before actually trying to close the door. This is much more efficient.&lt;/p&gt;

&lt;p&gt;Here's another scenario:&lt;/p&gt;

&lt;p&gt;Imagine you're implementing a search feature that fetches results as a user types:&lt;/p&gt;

&lt;p&gt;Without debouncing:&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="c1"&gt;// typing "javascript"&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;j&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jav&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javasc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascrip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would make 10 API calls. Most of them useless since the user is still typing.&lt;/p&gt;

&lt;p&gt;With debouncing (300ms delay):&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="c1"&gt;// typing "javascript"&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;j&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jav&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;java&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javas&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javasc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascr&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascri&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascrip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;API&lt;/span&gt; &lt;span class="nf"&gt;call &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;only&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt; &lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt; &lt;span class="nx"&gt;after&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="nx"&gt;stops&lt;/span&gt; &lt;span class="nx"&gt;typing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debouncing is like telling your code: "Wait until the user has stopped doing something for X milliseconds before actually running this function."&lt;/p&gt;

&lt;p&gt;Here's the solution to LeetCode #2627:&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="cm"&gt;/**
 * @param {Function} fn
 * @param {number} t milliseconds
 * @return {Function}
 */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;debounce&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;t&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;timeoutID&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;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timeoutID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// MDN reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/clearTimeout&lt;/span&gt;
    &lt;span class="nx"&gt;timeoutID&lt;/span&gt; &lt;span class="o"&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="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&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;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;t&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="c1"&gt;// tests&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;debounce&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="nx"&gt;log&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="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="s2"&gt;Starting tests...&lt;/span&gt;&lt;span class="dl"&gt;"&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="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="s2"&gt;Test 1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// should be cancelled&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="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="s2"&gt;Test 2&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// should be cancelled&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="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="s2"&gt;Test 3&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// should be logged at t=300ms&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="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="s2"&gt;Tests completed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Explanantion:&lt;/span&gt;
&lt;span class="c1"&gt;// - we create a closure where timeoutID persists between calls&lt;/span&gt;
&lt;span class="c1"&gt;// - timeoutID starts out as null&lt;/span&gt;
&lt;span class="c1"&gt;// - we return the debounced version of the initial function&lt;/span&gt;

&lt;span class="c1"&gt;// const log = debounce(console.log, 100);&lt;/span&gt;
&lt;span class="c1"&gt;// - this^ creates a new closure with its own timeoutID&lt;/span&gt;
&lt;span class="c1"&gt;// - log is now the inner function&lt;/span&gt;

&lt;span class="c1"&gt;// setTimeout(() =&amp;gt; log("Test 1"), 50);  // at t=50ms&lt;/span&gt;
&lt;span class="c1"&gt;// setTimeout(() =&amp;gt; log("Test 2"), 75);  // at t=75ms&lt;/span&gt;
&lt;span class="c1"&gt;// setTimeout(() =&amp;gt; log("Test 3"), 200); // at t=200ms&lt;/span&gt;

&lt;span class="c1"&gt;// t=50ms: &lt;/span&gt;
&lt;span class="c1"&gt;// - log("Test 1") called&lt;/span&gt;
&lt;span class="c1"&gt;// - clears timeoutId (null, so nothing happens)&lt;/span&gt;
&lt;span class="c1"&gt;// - sets new timeout to run at t=150ms&lt;/span&gt;

&lt;span class="c1"&gt;// t=75ms: &lt;/span&gt;
&lt;span class="c1"&gt;// - log("Test 2") called&lt;/span&gt;
&lt;span class="c1"&gt;// - clears previous timeout (cancels "Test 1")&lt;/span&gt;
&lt;span class="c1"&gt;// - sets new timeout to run at t=175ms&lt;/span&gt;

&lt;span class="c1"&gt;// t=200ms:&lt;/span&gt;
&lt;span class="c1"&gt;// - log("Test 3") called&lt;/span&gt;
&lt;span class="c1"&gt;// - clears previous timeout (cancels "Test 2")&lt;/span&gt;
&lt;span class="c1"&gt;// - sets new timeout to run at t=300ms&lt;/span&gt;

&lt;span class="c1"&gt;// t=300ms:&lt;/span&gt;
&lt;span class="c1"&gt;// - finally executes fn("Test 3")&lt;/span&gt;


&lt;span class="c1"&gt;// why this works:&lt;/span&gt;
&lt;span class="c1"&gt;// - the closure keeps timeoutId alive between calls&lt;/span&gt;
&lt;span class="c1"&gt;// - every new call cancels the previous timeout&lt;/span&gt;
&lt;span class="c1"&gt;// - only the last scheduled timeout actually runs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other common real-world use cases for debouncing (apart from search bars):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Save drafts (wait until user stops editing)&lt;/li&gt;
&lt;li&gt;Submit button (prevent double submissions)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What It Gets Wrong
&lt;/h2&gt;

&lt;p&gt;I hope that, from the overall positive tone of this article, my opinion on &lt;strong&gt;30 Days of JS&lt;/strong&gt; has become clear by now. &lt;/p&gt;

&lt;p&gt;But no educational resource is perfect, and, when it comes to limitations, honesty is valuable. This study plan has several blind spots worth examining.&lt;/p&gt;

&lt;p&gt;First, the study plan assumes a certain level of prior knowledge. &lt;br&gt;
If you're not already comfortable with JavaScript, some of the challenges can be overwhelming. This can be discouraging for beginners who might have had other expectations from the study plan.&lt;/p&gt;

&lt;p&gt;Second of all, the challenges are presented in an isolated manner. &lt;br&gt;
This makes sense in the beginning, but can be a disappointing thing to realize as you progress through the plan. Real-world problems often require combining multiple patterns and techniques. The study plan could benefit from more integrated challenges that require using several concepts together (exception: we do use closures all throughout the plan). These could fit well in the Bonus section (which is already reserved to premium users).&lt;/p&gt;

&lt;p&gt;At last, the main weakness of this set of challenges lies in its concept explanations. Coming from competitive programming, &lt;br&gt;
I'm used to clear definitions of new terms and concepts in problem statements. However, LeetCode's descriptions are often unnecessarily complex - understanding their explanation of a debounced function is harder than implementing the actual solution.&lt;/p&gt;

&lt;p&gt;Despite its shortcomings, the study plan is a valuable resource for understanding modern JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beyond the 30 Days
&lt;/h2&gt;

&lt;p&gt;Understanding these patterns is just the beginning. &lt;br&gt;
The real challenge is recognizing when and how to apply them in production code. Here's what I've discovered after encountering these patterns in the wild.&lt;/p&gt;

&lt;p&gt;First, these patterns rarely appear in isolation. Real codebases combine them in ways the challenges can't explore. Consider a search feature, implemented from scratch. You might find yourself using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debounce for input handling&lt;/li&gt;
&lt;li&gt;Memoization for result caching&lt;/li&gt;
&lt;li&gt;Promise timeouts for API calls&lt;/li&gt;
&lt;li&gt;Event emitters for search state management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these patterns interact, creating complexity that no single challenge prepares you for. But, having implemented each piece yourself, you get a general idea of how the whole implementation is supposed to function.&lt;/p&gt;

&lt;p&gt;Counterintuitively, the most valuable skill you will gain isn't implementing these patterns - it is recognizing them in other people's code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;After completing this study plan, coding interviews aren't the only place where you'll recognize these patterns.&lt;/p&gt;

&lt;p&gt;You'll spot them in open source code, in your colleagues' pull requests, and might start noticing them in your past projects. You might had implemented them before, without even realizing it. Most importantly, you'll understand why they're there.&lt;/p&gt;

&lt;p&gt;What started as puzzle-solving transformed into a deeper understanding of modern JavaScript's ecosystem.&lt;/p&gt;

&lt;p&gt;That's the gap this study plan fills: bridging theoretical knowledge with practical engineering wisdom.&lt;/p&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/debounce/description/?envType=study-plan-v2&amp;amp;envId=30-days-of-javascript" rel="noopener noreferrer"&gt;2627. Debounce&lt;/a&gt; (Promises and Time) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/event-emitter/description/?envType=study-plan-v2&amp;amp;envId=30-days-of-javascript" rel="noopener noreferrer"&gt;2694. Event Emitter&lt;/a&gt; (Classes) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/memoize/?envType=study-plan-v2&amp;amp;envId=30-days-of-javascript" rel="noopener noreferrer"&gt;2623. Memoize&lt;/a&gt; (Function Transformations) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://leetcode.com/problems/promise-pool/description/" rel="noopener noreferrer"&gt;2636. Promise Pool&lt;/a&gt; (Bonus) ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

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