How to lazyload Javascript using LocalStorage

Lazy load JavaScript with LocalStorage to improve website speed, reduce bandwidth, and enhance user experience. Simple guide with examples.
Hello! Welcome to EmadulAi.

Website performance plays a crucial role in ensuring a smooth and enjoyable user experience. One proven technique to improve performance is lazy loading JavaScript. Lazy loading means loading JavaScript files only when they are needed, which helps reduce initial page load time and conserve bandwidth.

In this tutorial, we’ll take a unique approach to lazy loading by using LocalStorage, a powerful web storage feature available in modern browsers. By the end of this guide, you’ll gain a clear understanding of how to implement lazy loading with LocalStorage and significantly optimize your website’s performance.

I have written a JavaScript library that can be used to lazy load resources. To use it, simply paste the following JavaScript code inside the <head> section of your webpage:


/*!
 * lazy.js by Fineshop Design
 * ----------------------------
 *
 * MIT License
 *
 * Copyright (c) 2021 Fineshop Design
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
window.lazy =
  window.lazy ||
  new Promise((resolve) => {
    const LOCAL_KEY = "IS_LAZIED";
    const LOCAL_VALUE = "true";
    // Window events to be attached initially which can trigger lazy
    const WINDOW_INITIAL_EVENTS = ["scroll", "click"];
    // Window events to be attached after window is fully loaded which can trigger lazy
    const WINDOW_ONLOAD_EVENTS = [
      "keydown",
      "mouseover",
      "touchmove",
      "touchstart",
    ];
    // All window events which will be attached
    const WINDOW_EVENTS = WINDOW_INITIAL_EVENTS.concat(WINDOW_ONLOAD_EVENTS);

    function getLazied() {
      try {
        return localStorage.getItem(LOCAL_KEY) === LOCAL_VALUE;
      } catch (_) {
        return true;
      }
    }
    function setLazied(lazied = true) {
      try {
        if (lazied) {
          localStorage.setItem(LOCAL_KEY, LOCAL_VALUE);
        } else {
          localStorage.removeItem(LOCAL_KEY);
        }
      } catch (_) {
        // do nothing
      }
    }
    function execute(data) {
      setLazied(true);
      resolve({ type: data.type.toLowerCase() });
      // detach event listeners
      for (const type of WINDOW_EVENTS) {
        window.removeEventListener(type, execute);
      }
    }
    if (getLazied()) {
      resolve({ type: "local" });
    } else {
      // check if document is already scrolled
      if (
        document.documentElement.scrollTop !== 0 ||
        (document.body && document.body.scrollTop !== 0)
      ) {
        execute({ type: "scroll" });
      } else {
        // events to be attached after window is loaded
        const onLoad = () => {
          window.removeEventListener("load", onLoad);
          for (const type of WINDOW_ONLOAD_EVENTS) {
            window.addEventListener(type, execute);
          }
        };
        window.addEventListener("load", onLoad);

        // events to be attached initially
        for (const type of WINDOW_INITIAL_EVENTS) {
          window.addEventListener(type, execute);
        }
      }
    }
  });

Usage,

The lazy promise is resolved when the user interacts with the page (e.g., scroll, click, keypress, mouseover, or touch events). Once the promise is resolved, you can safely load your external JavaScript, stylesheets, or make HTTP requests.


lazy.then((e) => {
  // Load your JS or CSS dynamically
  // Make HTTP requests
  console.log(e.type) // could be 'scroll', 'click', 'keydown', 'mouseover', 'touchmove', 'touchstart' or 'local'
});

Examples

Here I have written a Javascript function loadJS to load Javascript from external sources dynamically. ata thik ache


/**
 * Function to load Javascript file
 *
 * @author Deo Kumar <[email protected]>
 *
 * @param {string | URL} source - Source of the script
 * @param {((script: HTMLScriptElement) => void) | null} [beforeLoad] - Function for modifying script element before loading
 *
 * @returns {Promise<HTMLScriptElement>} - Returns a Promise which resolves with HTMLScriptElement instance
 */
window.loadJS = function loadJS(source, beforeLoad) {
  return new Promise((resolve, reject) => {
    const script = document.createElement("script");

    // Enable async and defer by default
    Object.assign(script, { async: true, defer: true });

    if (typeof beforeLoad === "function") {
      beforeLoad(script);
    }

    function cleanUp() {
      script.onload = null;
      script.onerror = null;
    }

    script.src = source instanceof URL ? source.href : source;
    script.onload = (e) => {
      cleanUp();
      resolve(e.target);
    };
    script.onerror = (e) => {
      cleanUp();
      reject(new URIError(`The script ${e.target.src} didn't load correctly.`));
    };

    const firstScript = document.getElementsByTagName("script")[0];

    if (firstScript && firstScript.parentNode) {
      firstScript.parentNode.insertBefore(script, firstScript);
    } else {
      document.head.appendChild(script);
    }
  });
}

We can use it inside our lazy.then() callback function as shown below:


lazy.then(() => { 
  return loadJS("./my-example-script.js", (script) => {
    // Add async attribute before loading
    script.async = true;
  });
}).then(() => {
  // JS is lazyloaded, perform actions here
  // myExampleLib.myMethod();
});

Lazyload AdSense Script

You can lazy load the Google AdSense script using this library. Here’s an example:


lazy.then(() => {
  const adsenseScriptSource = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXXXXXXXXXXXXX";
  return loadJS(adsenseScriptSource, (script) => {
    script.async = true;
    script.crossOrigin = "anonymous";
  });
}).then(() => {
  // Adsense script loaded
  // ...
});
Conclusion Lazy loading JavaScript with LocalStorage is a powerful technique to boost website performance and deliver a smoother user experience. By deferring the loading of non-essential scripts until they are actually needed, you can significantly improve initial page load speed and reduce unnecessary bandwidth usage. With the approach covered in this tutorial, you’ll be able to implement lazy loading effectively and build faster, more efficient, and user-friendly websites.

About the author

Emadul Tarafdar
Hello guys! My name is Emadul Tarafdar. If you enjoy my content, feel free to follow me on my social media links. Thanks so much for your support!

Post a Comment

Join the conversation