<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Arunkumarvelu]]></title><description><![CDATA[Arunkumarvelu]]></description><link>https://blogs.arunkumarvelu.com</link><generator>RSS for Node</generator><lastBuildDate>Wed, 29 Apr 2026 14:06:16 GMT</lastBuildDate><atom:link href="https://blogs.arunkumarvelu.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[How throttle and debounce timing functions can optimize your script performance]]></title><description><![CDATA[In JavaScript, timing functions like throttle and debounce give developers control over the rate at which a function is called. Timing functions are now considered as one of the fundamental techniques that every web developer must know. By controllin...]]></description><link>https://blogs.arunkumarvelu.com/how-throttle-and-debounce-timing-functions-can-optimize-your-script-performance</link><guid isPermaLink="true">https://blogs.arunkumarvelu.com/how-throttle-and-debounce-timing-functions-can-optimize-your-script-performance</guid><category><![CDATA[throttling]]></category><category><![CDATA[throttling in javascript]]></category><category><![CDATA[debouncing]]></category><category><![CDATA[Debounce and Throttling]]></category><dc:creator><![CDATA[Arun kumar Velu]]></dc:creator><pubDate>Fri, 12 Dec 2025 13:18:12 GMT</pubDate><content:encoded><![CDATA[<p>In JavaScript, timing functions like throttle and debounce give developers control over the rate at which a function is called. Timing functions are now considered as one of the fundamental techniques that every web developer must know. By controlling how often an event is called, they have a significant effect on the performance of scripts. Timing functions are especially useful when working on event handler assignments. </p>
<p>As developers, we have to deal with various—and sometimes unforeseen—scenarios while coding. A lot of times, we might have to invoke functions even when it’s not necessary. Consider a scenario where you want to execute a callback for resizing a window. Does it make sense to fire the callback as you resize? Most likely not. You should wait until the user has finished interacting with the tool, and then fire the callback. This might seem like common sense but as the complications increase, it might be a tall task to execute this without using timing functions.</p>
<p>Considering that there is still a lot of confusion around the concepts of  debouncing and throttling (including where to use it, and how it works), I have simplified these concepts in this blog so that you can optimize the performance of your scripts with ease.</p>
<p><strong>How throttle and debounce timing functions differ</strong></p>
<p>Throttle and debounce are both timing functions that limit the number of function calls. The difference lies in the way they operate.</p>
<p><strong>Throttle</strong>: When there is a continuous function call, throttle runs a given function just once in a given period.</p>
<p>Throttle is useful for cases where users carry out a smooth or continuous event, such as scrolling or resizing. In the event of animating elements based on their scroll position or handling an infinite scroll page, we can use throttle to control how often the scroll handler is called.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765545000467/ce216f8f-40cd-4ea3-b1ba-f6bc692bc58f.gif" alt class="image--center mx-auto" /></p>
<p><strong>Debounce</strong>: When there is a continuous user event call, debounce calls a function when a user hasn’t carried out an event in a specific amount of time.</p>
<p>Debouncing is a good method for controlling events that require sporadic user actions, such as keying in an input field or clicking a button. In the case of a search bar that makes API calls according to user input, implementing a debounce is a good way to reduce the number of calls made to the API.</p>
<p>The following video snippet displays how you can see as many API calls on each keypress without using the debounce function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765545031790/5812c0b9-87fa-4c88-8c30-1ce241a8a6b7.gif" alt class="image--center mx-auto" /></p>
<p>The following video snippet shows how you can perform just a few API calls with debounce to get the same results.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765545056618/714486fc-3312-4f20-8990-b0224f8f809f.gif" alt class="image--center mx-auto" /></p>
<p><strong>Why we use throttle and debounce timing functions</strong></p>
<p>Timing functions are used to protect resources while improving their performance. Throttle and debounce allows you to  call a function fewer times than you would in a storm of events. Debounce and throttle are two methods for optimizing performance of scripts by controlling how often an event is called.</p>
<p>In Freshdesk Messaging, we have used these two techniques in various places to improve user experience and product performance.</p>
<p>Here, I would like to share one of the scenarios where we use the debouncing logic. In the Freshdesk messaging tool, we have an inbox where agents can send and receive messages. Agents can highlight placeholders in the editor so that when they send the message, the system replaces the placeholder with the actual message.  </p>
<p>Previously, we would check for regular expression (regex) matches on each keypress in the editor to identify and highlight if the content was a placeholder. On each keypress, the system parsed  the entire content with regex to find the placeholder match. The downside to this was that regex matches on each keypress degraded the user typing experience. We also needed to highlight the content that the user typed in the placeholder at the same time. </p>
<p>That was when we decided to use the debounce logic on keypress. </p>
<p>Now, when a user is not typing for a few milliseconds, we call the debounce logic performing the parsing function and replace the logic. These timing functions are very useful when it comes to optimizing performance and user experience.</p>
<p><strong>How you can implement your own timing functions</strong></p>
<p>By using the functions, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">closures</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call</a>, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">apply</a>, and <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout</a>, in JavaScript, we’ll show how you can implement your own timing functions. </p>
<p><strong>Using the throttle timing function</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> throttle = <span class="hljs-function">(<span class="hljs-params">callback, interval</span>) =&gt;</span> {
   <span class="hljs-keyword">let</span> timer;
   <span class="hljs-keyword">let</span> allowEvents = <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
     <span class="hljs-keyword">let</span> context = <span class="hljs-built_in">this</span>;
     <span class="hljs-keyword">let</span> args = <span class="hljs-built_in">arguments</span>;
      <span class="hljs-keyword">if</span> (allowEvents) {
       callback.apply(context, args)
       allowEvents = <span class="hljs-literal">false</span>;
       <span class="hljs-built_in">clearTimeout</span>(timer);
       timer = setTimeOut(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
         allowEvents = <span class="hljs-literal">true</span>
       }, interval)
     }
   }
 }
</code></pre>
<p>You can also check out an example on this <a target="_blank" href="https://codepen.io/arunkumarvelu/pen/gOWQYwe">CodePen link</a></p>
<p><strong>Using the debounce timing function</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> debounce = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">callback, interval</span>) </span>{
   <span class="hljs-keyword">let</span> timer;
   <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
       <span class="hljs-built_in">clearTimeout</span>(timer)
       timer = <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
         callback.apply()
       }, interval)
    }
}
</code></pre>
<p>You can also check out an example on this <a target="_blank" href="https://codepen.io/arunkumarvelu/pen/vYmQYoY">CodePen link</a></p>
<p><strong>Timing ahead</strong></p>
<p>You should now have a better understanding of timing functions and the differences between throttling and debouncing. We’ve also explored the logical approaches and the code implementation of both of these methods so you can apply them to real-life situations and optimize the performance of your scripts.</p>
<p><strong>References</strong>: </p>
<ol>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20220526052510/https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20220526052510/https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout</a></p>
</li>
</ol>
]]></content:encoded></item><item><title><![CDATA[Optimize Image Loading Performance with Intersection Observer]]></title><description><![CDATA[The majority of software engineers today would love to focus on the latest and greatest framework, technology, or library. However, not many of these engineers would care to look at some basics of the trade that can immediately improve the loading ti...]]></description><link>https://blogs.arunkumarvelu.com/lazy-load-images-intersection-observer</link><guid isPermaLink="true">https://blogs.arunkumarvelu.com/lazy-load-images-intersection-observer</guid><category><![CDATA[webperformance]]></category><category><![CDATA[IntersectionObserver]]></category><category><![CDATA[lazyload]]></category><dc:creator><![CDATA[Arun kumar Velu]]></dc:creator><pubDate>Wed, 10 Dec 2025 06:36:45 GMT</pubDate><content:encoded><![CDATA[<p>The majority of software engineers today would love to focus on the latest and greatest framework, technology, or library. However, not many of these engineers would care to look at some basics of the trade that can immediately improve the loading time of web apps. One such technique is ‘image lazy load’ levering lazy loading images, which happens when the images are outside the viewport. You can read more about lazy loading images <a target="_blank" href="https://web.archive.org/web/20210227041703/https://css-tricks.com/the-complete-guide-to-lazy-loading-images/">here</a>.</p>
<p>The Internet is full of ways to improve the performance of your web applications, but the most popular ones are CDN, image compression, and lazy loading.</p>
<p>In this blog, we will talk about tackling lazy load images with Intersection Observer API. By leveraging lazy loading images, we managed to save around 200% data and reduce the app loading time to 68%.  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765346872414/fc601f5b-2cfa-41c9-929f-472b86656e60.gif" alt class="image--center mx-auto" /></p>
<h3 id="heading-what-is-image-lazy-load"><strong>What is image lazy load?</strong></h3>
<p>Usually in &lt;img&gt; when we type in the URL, it automatically downloads images even if it is outside the viewport. By using <strong>Intersection Observer</strong> we can download and render images on demand when the image DOM intersects with the viewport.</p>
<h3 id="heading-what-is-intersection-observer"><strong>What is Intersection Observer?</strong></h3>
<p>The Intersection Observer API provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document’s viewport, which was introduced in <a target="_blank" href="https://web.archive.org/web/20210227041703/https://www.w3.org/TR/intersection-observer/">2017</a>. </p>
<h3 id="heading-why-did-we-choose-intersection-observer"><strong>Why did we choose Intersection Observer?</strong></h3>
<p>Intersection Observer is the more popular method for visibility detection over more traditional methods, such as onScroll + getBoundingClientRect() because <em>the actual detection implementation doesn’t run on the main thread.</em> However, the callback for when an intersection has been triggered does run on the main thread so remember to keep it light!</p>
<p>For context, I’m going to share with you the problem we faced with Freshchat and how we fixed it using Intersection Observer. Before delving into the details, I would first like to share the results of our fix. With Optimization Observer, we saved around 67% of data that was not in viewport. As a result of the data reduction, we managed to reduce DOM manipulation, and decrease the loading time of the app to 68%.</p>
<p>When user log in, they land on the Inbox page, which contains a list of conversations with visitor images. Every conversation has agents and visitors with profile images who are involved in this conversation, and also messages containing images. By using Intersection Observer, images are lazy loaded to improve the performance of the app.</p>
<h3 id="heading-how-can-you-implement-it"><strong>How can you implement it?</strong></h3>
<p>It’s simple. Just follow these steps:</p>
<p>In <strong>HTML</strong>,</p>
<p> Add the image url to data-src instead of src in &lt;img&gt; </p>
<p><em>Note: If we add it directly to src, the browser automatically starts the download.</em>  </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765346949494/7910025b-9811-4a0c-a73c-afc9a2d4ba8f.png" alt class="image--center mx-auto" /></p>
<p>In <strong>Javascript</strong>,</p>
<p>Create a new instance of Intersection Observer with the callback function ‘observe’. Ask an observer to observe that image element.</p>
<p>Notice when an intersection was triggered between the root and target elements. In our case, the elements were the top-level document’s viewport and img.lazy ref respectively.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765347034468/ea43b785-0d70-409c-b269-4d3094952e78.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765347080225/baf1dd37-f373-4334-ba66-99bd5bd060f7.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-before-image-lazy-load"><strong>Before image lazy load</strong></h3>
<p>We downloaded all the images from all 40 conversations, visitor images, and selected conversations with images even those that were not in viewport. The total data we have downloaded is <strong>1.1MB of image resources</strong> and also the <strong>time taken to render was 3.45s.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765348231854/b9356c54-7bde-4801-b23a-cf825b768c65.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-after-image-lazy-load"><strong>After image lazy load</strong></h3>
<p>The total data we have downloaded was <strong>373KB of image resources</strong> and also <strong>time taken to render was 2.31s.</strong> Around <strong>200%</strong> of bandwidth usage was saved, reducing the loading time of the app to <strong>68%</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1765348278473/58342c79-fe1e-46cd-bf24-867ed8c0d796.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>Using Intersection Observer API, we saved around ~740KB of data, ~1.14s of rendering time. We successfully reduced LCP to ~2.9s and interactive and blocking time. Around <strong>200%</strong> of bandwidth usage was saved and the loading time of the app was brought down to <strong>68%</strong>.</p>
<p>This is a better approach than the traditional way of dealing with lazy load because—and I reiterate—the actual detection implementation <em>doesn’t</em> run on the main thread.</p>
<p><strong>References:</strong> </p>
<ol>
<li><p><a target="_blank" href="https://web.archive.org/web/20210227041703/https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API">https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API</a></p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20210227041703/https://developers.google.com/web/updates/2016/04/intersectionobserver">https://developers.google.com/web/updates/2016/04/intersectionobserver</a> </p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20210227041703/https://medium.com/walmartglobaltech/lazy-loading-images-intersectionobserver-8c5bff730920">https://medium.com/walmartglobaltech/lazy-loading-images-intersectionobserver-8c5bff730920</a> </p>
</li>
<li><p><a target="_blank" href="https://web.archive.org/web/20210227041703/https://github.com/topaxi/ember-img-lazy">https://github.com/topaxi/ember-img-lazy</a></p>
</li>
</ol>
]]></content:encoded></item></channel></rss>