Varadan13

Go Back
Last updated on

Lazy loading


type LazyLoadOptions =
  | {
      on: "visible";
      target: HTMLElement;
      delay?: never;
      rootMargin?: string;
      threshold?: number;
    }
  | {
      on: "delay";
      target: HTMLElement;
      delay: number;
      rootMargin?: never;
      threshold?: never;
    }
  | {
      on: "idle" | "click" | "mousemove";
      target: HTMLElement;
      delay?: never;
      rootMargin?: never;
      threshold?: never;
    };
export function lazyLoad(importer, options) {
  const {
    on = "visible",
    target,
    delay,
    rootMargin = "0",
    threshold = 0,
  } = options;

  const load = () => importer();

  switch (on) {
    case "idle":
      if ("requestIdleCallback" in window) {
        requestIdleCallback(() => load());
      } else {
        setTimeout(() => load(), 2000);
      }
      break;

    case "delay":
      setTimeout(() => load(), delay);
      break;

    case "click":
      const onClick = () => {
        load();
        target.removeEventListener("click", onClick);
      };
      target.addEventListener("click", onClick);
      break;

    case "mousemove":
      const onMousemove = () => {
        load();
        target.removeEventListener("mousemove", onMousemove);
      };
      target.addEventListener("mousemove", onMousemove);
      break;

    case "visible":
      const observer = new IntersectionObserver(
        (entries, obs) => {
          entries.forEach(entry => {
            if (entry.isIntersecting) {
              load();
              obs.disconnect();
            }
          });
        },
        {
          rootMargin,
          threshold,
        }
      );
      observer.observe(target);
      break;

    default:
      throw new Error("Unsupported event type: " + on);
  }
}