@shinsenter/defer.js

🥇 A super small, super efficient library that helps you lazy load almost everything like images, video, audio, iframes as well as stylesheets, and JavaScript.

Usage no npm install needed!

<script type="module">
  import shinsenterDeferJs from 'https://cdn.skypack.dev/@shinsenter/defer.js';
</script>

README

Package @shinsenter/defer.js

🥇 A super small, super efficient library that helps you lazy load almost everything like images, video, audio, iframes as well as stylesheets, and JavaScript.

NPM Snyk Vulnerabilities for npm package CodeFactor Grade


GitHub Release Date GitHub package.json version npm bundle size (scoped) jsDelivr hits (npm)

NPM


Use cases

In real life, many resources and third-party scripts, such as jQuery, are used to enhance our website to add additional interactivity, animations, and other effects.

Unfortunately, third-party scripts usually block page rendering and further downloading resources of the page.

There is a common knowledge that you should use <script src="..." async> (or <script src="..." defer>) and/or put your scripts at the very bottom of the page, so that as much as possible of the page gets loaded and rendered to the user, as fast as possible.

But in various cases, using async or defer attributes does not deliver faster page speed than defer.js does. Furthermore defer.js also gives you very simple ways to flexibly optimize other resources in your website.

Why you should consider defer.js

  • ⚡️ Under 1KB (mingzipped size)
  • 🚀 Native API, blazing fast
  • 👍 No dependencies, no jQuery
  • 🧩 Lazy load almost everything
  • 🎯 Core Web Vitals friendly
  • 🔰 Very easy to use
  • 📱 Smartphone browser friendly
  • ✅ Supports legacy browsers (IE9+)
  • 🤝 Works well with your favorite frameworks

Browser support

Works perfectly on modern browsers. Lazy-loading is also available for Internet Explorer 9 * (with IntersectionObserver polyfill library) and later.

  • 🖥 IE9+ / Microsoft EDGE
  • 🖥 Firefox 4+
  • 🖥 Safari 3+
  • 🖥 Chrome
  • 🖥 Opera
  • 📱 Android 4+
  • 📱 iOS 3.2+

Getting started

Basic

Add defer.min.js from this library into your HTML page, just below the opening <head> tag.

You may download a ZIP of this library, or load it from a CDN like below example.

<head>
  <meta charset="UTF-8" />
  <title>My Awesome Page</title>

  <!-- Put defer.min.js here -->
  <script id="defer-js" src="https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.5.0/dist/defer.min.js"></script>

  <!-- ... -->
</head>

Compatibility with previous releases

I strongly recommend that you should migrate to the latest version for better performance.

If you have no time and want to ensure compatibility with older version, use defer_plus.min.js instead of defer.min.js.

<head>
  <meta charset="UTF-8" />
  <title>My Awesome Page</title>

  <!-- Put defer_plus.min.js here -->
  <script id="defer-js" src="https://cdn.jsdelivr.net/npm/@shinsenter/defer.js@2.5.0/dist/defer_plus.min.js"></script>

  <!-- ... -->
</head>

Inlining the library

Since size of defer.js library is optimized to minimum size, you can inline entire library in the <head> of the HTML document to minimize the number of requests.

<head>
  <meta charset="UTF-8" />
  <title>My Awesome Page</title>

  <!-- Inlining defer.min.js -->
  <script id="defer-js">/* content of defer.min.js will be here */</script>

  <!-- ... -->
</head>

For OLD browsers (such as IE9)

To take advantage of native performance for older browsers that doesn't support this feature (such as IE9), you should load IntersectionObserver polyfill library right after the defer.min.js script tag as following example:

<!-- To support older browsers such as Internet Explorer 9 -->
<!-- Please put IntersectionObserver polyfill right after defer.js script tag -->
<script id="polyfill-js">'IntersectionObserver'in window||document.write('<script src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver"><\/script>');</script>

Note: most of modern browsers support IntersectionObserver feature, so you don't have to concern about it.

Functions

Typedefs

Defer(func, [delay]) ⇒ void

This function is used when you want to defer a JavaScript code block and reduce the impact of its execution on page load performance.

A JavaScript block called by the Defer() function is always guaranteed to be executed after your web page has completely loaded other essential resources.

Kind: global function
Since: 2.0

Param Type Default Description
func function The function that will be deferred.
[delay] number 0 The duration in miliseconds to delay the func function.

Example
Basic example.

Defer(function() {
  // Put JavaScript code block here
  // and it will be executed after your page has finished loading.
  runMyHeavyFunction();
  runLongTasks();
  // or
  runMyAjaxRequests();
  connectTo3rdPartyServices();
});

Example
The jQuery's get and fadeIn() functions often affect DOM structure of web page and slows down page performance. Calling fadeIn() with Defer() will reduce the impact significantly.

Defer(function() {
  // A common example of using jQuery functions.
  // These functions may affect DOM structure if not deferred.
  jQuery.get('https://appseeds.net/api', function(result) {
    jQuery('#mydiv').hide().append(result);
    jQuery('#mydiv').fadeIn().show();
  });
}, 2000);
// The number 2000 means Defer() will delay execution
// of above jQuery functions after 2000ms when the page has finished loading.

Defer.all([selector]) ⇒ void

Applying above Defer() function to all script tags on your website may take time. The Defer.all() function below can be a great help.

Simply replace the type attribute of script tags to type="deferjs" and this library will automatically lazyload all script tags with this attribute attached.

By default, the Defer.all() function is triggered automatically.

Kind: static method of Defer
Since: 2.0

Param Type Default Description
[selector] string "[type=deferjs]" A CSS selector that queries script tags will be deferred.

Example
Basic usage.

Before:

<script type="text/javascript" src="/path/to/external-javascript.js"></script>
<script>
  // Example of JavaScript code block
</script>

After replacing type attributes to type="deferjs":

<script type="deferjs" src="/path/to/external-javascript.js"></script>
<script type="deferjs">
  // Example of JavaScript code block
</script>

Example
If you don't want to use type="deferjs" syntax, you can easily choose your own name.

This example uses type="myjs" instead of type="deferjs":

<script type="myjs" src="/path/to/heavy-javascript.js"></script>
<script type="myjs">
  // Some heavy DOM manipulations here
</script>

<!-- HTML content trimmed -->

<!-- Call Defer.all() after all other script tags -->
<script>Defer.all('script[type="myjs"]');</script>

Important note: make sure Defer.all('script[type="myjs"]'); is placed after all other script tags, such as very bottom of the body tag.


Defer.js(src, [id], [delay], [callback]) ⇒ void

For lazy loading external JavaScript files.

This function is useful when you don't want heavy JavaScript (especially the widgets of social networks, ad services) to affect your website loading speed.

Kind: static method of Defer
Since: 2.0

Param Type Default Description
src string URL to the js file that should be lazy loaded.
[id] string The ID will be assigned to the script tag to avoid downloading the same file multiple times.
[delay] number 0 The duration in miliseconds to delay loading the js file.
[callback] Closure The callback function will be executed if the js file is successfully loaded.

Example
Delay loading of Facebook SDK after 3000ms. Then use a callback function trigger a Share dialog.

window.fbAsyncInit = function() {
  FB.init({
    appId            : 'your-app-id',
    autoLogAppEvents : true,
    xfbml            : true,
    version          : 'v11.0'
  });
};

Defer.js('https://connect.facebook.net/en_US/sdk.js', 'fb-sdk', 3000, function () {
  // trigger a Share dialog when the SDK loaded
  FB.ui({
    method: 'share',
    href: 'https://developers.facebook.com/docs/'
  }, function(response){});
});

Defer.css(src, [id], [delay], [callback]) ⇒ void

For lazy loading external CSS files.

This function is useful when you don't want heavy CSS (like Web Fonts) to affect your website loading speed.

Kind: static method of Defer
Since: 2.0

Param Type Default Description
src string URL to the css file that should be lazy loaded.
[id] string The ID will be assigned to the script tag to avoid downloading the same file multiple times.
[delay] number 0 The duration in miliseconds to delay loading the css file.
[callback] Closure The callback function will be executed if the css file is successfully loaded.

Example
Lazy load FontAwesome Webfont from its CDN.

Defer.css('https://pro.fontawesome.com/releases/v5.10.0/css/all.css', 'fa5-css');

Example
Delay loading animate.css from CDN, then use a callback function to add some animations to h1 tag.

Defer.css('https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css', 'animate-css', 1000, function () {
  jQuery('h1').addClass('animate__animated animate__bounce');
});

Defer.dom([selector], [delay], [revealedClass], [validator], [observeOptions]) ⇒ void

For lazy loading attributes of any element on web page.

Basically, this library use a feature called IntersectionObserver to reveal an element when user is scrolling to the position where it appears within the browser's viewport.

The Defer.dom function also converts its data-* attributes into regular attributes (e.g. from data-src to src), so you can use this to lazyload your images and iframes as well.

Kind: static method of Defer
Since: 2.0

Param Type Default Description
[selector] string "[data-src]" A CSS selector that queries elements will be lazy loaded.
[delay] number 0 The duration in miliseconds to delay the lazy loading for the elements.
[revealedClass] string A CSS class will be added automatically after when an element has been successfully revealed.
[validator] Closure A function will be executed with element will be lazy loaded as its argument. If the function returns false, lazy loading for that element will be skipped.
[observeOptions] object Intersection observer options

Example
Basic usage: Lazy load all <img> tags which have CSS class lazy.

<script>Defer.dom('img.lazy');</script>

<!-- Here may be a very long content -->

<img class="lazy" alt="Photo 1" data-src="https://picsum.photos/200/300?random=1" width="200" height="300" />
<img class="lazy" alt="Photo 2" data-src="https://picsum.photos/200/300?random=2" width="200" height="300" />
<img class="lazy" alt="Photo 3" data-src="https://picsum.photos/200/300?random=3" width="200" height="300" />

Example
Basic usage: Lazy load background image of a div tag.

<style>
  #my_div {
  width: 300px;
  height: 200px;
  }
</style>

<script>
  // Lazy load div tag which has id="my_div"
  Defer.dom('#my_div');
</script>

<!-- Here may be a very long content -->

<div id="my_div"
  data-style="background: url(https://img.youtube.com/vi/Uz970DggW7E/hqdefault.jpg) 50% 50% / cover no-repeat;">
  <!-- The content -->
</div>

Example
Advanced usage: Delay lazy loading <img> tags 200ms after the page has completely loaded. Then it will add a CSS class loaded to the fully lazy loaded image element.

<script>Defer.dom('img.lazy', 200, 'loaded');</script>

<!-- Here may be a very long content -->

<img class="lazy" alt="Photo 1" data-src="https://picsum.photos/200/300?random=4" width="200" height="300" />
<img class="lazy" alt="Photo 2" data-src="https://picsum.photos/200/300?random=5" width="200" height="300" />
<img class="lazy" alt="Photo 3" data-src="https://picsum.photos/200/300?random=6" width="200" height="300" />

Example
Advanced usage: Lazy load with Intersection observer options

<script>
  // Preload images within 200% of the current viewport size.
  Defer.dom("img.early-lazy", 200, "loaded", null, {
  rootMargin: "200%"
  });
</script>

<!-- Here may be a very long content -->

<img class="early-lazy" alt="Photo 1" data-src="https://picsum.photos/200/300?random=7" width="200" height="300" />
<img class="early-lazy" alt="Photo 2" data-src="https://picsum.photos/200/300?random=8" width="200" height="300" />
<img class="early-lazy" alt="Photo 3" data-src="https://picsum.photos/200/300?random=9" width="200" height="300" />

Example
We can use CSS class that added to the lazy loaded element to add animation to the successfully loaded elements.

<script>Defer.dom('img.fade', 200, 'loaded');</script>
<style>
  img.fade {
    transition: opacity 500ms ease-in-out;
    opacity: 0;
  }
  img.fade.loaded {
    background: none;
    opacity: 1;
  }
</style>

<!-- Here may be a very long content -->

<img class="fade" alt="Photo 1" data-src="https://picsum.photos/200/300?random=10" width="200" height="300" />
<img class="fade" alt="Photo 2" data-src="https://picsum.photos/200/300?random=11" width="200" height="300" />
<img class="fade" alt="Photo 3" data-src="https://picsum.photos/200/300?random=12" width="200" height="300" />

Example
This function can be used similarly for other tags such as <iframe>, <video>, <audio>, <picture> tags.

<script>
  // Lazy load all elements which have CSS class `multi-lazy`
  Defer.dom('.multi-lazy', 200, 'loaded');
</script>

<!-- Here may be a very long content -->

<iframe class="multi-lazy" title="Youtube"
  width="400" height="300" allowfullscreen
  allow="accelerometer;autoplay;encrypted-media;gyroscope;picture-in-picture"
  data-style="background: url(https://img.youtube.com/vi/Uz970DggW7E/hqdefault.jpg) 50% 50% / cover no-repeat;"
  data-src="https://www.youtube.com/embed/Uz970DggW7E"></iframe>

<picture class="multi-lazy">
  <source media="(min-width:800px)" data-srcset="https://picsum.photos/800/1200">
  <source media="(min-width:600px)" data-srcset="https://picsum.photos/600/900">
  <img data-src="https://picsum.photos/200/300" alt="Photo" style="width:auto;">
</picture>

<audio class="multi-lazy" controls>
  <source data-src="sound.ogg" type="audio/ogg">
  <source data-src="sound.mp3" type="audio/mpeg">
  Your browser does not support the audio tag.
</audio>

<video class="multi-lazy" width="320" height="240" controls>
  <source data-src="movie.mp4" type="video/mp4">
  <source data-src="movie.ogg" type="video/ogg">
  Your browser does not support the video tag.
</video>

Example
Or even execute a piece of JavaScript when the user scrolls to the element #scroll_reveal.

<script>
  // Show an alert when user scrolled to #scroll_reveal
  Defer.dom('#scroll_reveal', null, null, function(element) {
    window.alert('You scrolled to #' + element.id);
  });
</script>

<!-- Here may be a very long content -->

<div id="scroll_reveal">
  This is my content.
</div>

Example
Combine with other Defer functions. Delay loading highlightjs library for 1000ms. Then when you scroll to any code tag, enable code highlighting for it.

var base = 'https://cdn.jsdelivr.net/npm/highlightjs@9.12.0';
Defer.css(base + '/styles/rainbow.css', 'hljs-css', 1000);
Defer.js(base + '/highlight.pack.min.js', 'hljs-js', 1000, function () {
  Defer.dom('pre code', 0, 'ide-loaded', function (block) {
    hljs.highlightBlock(block);
  });
});

Defer.reveal(element, [revealedClass]) ⇒ void

Reveal an element which is lazyloaded by the library

Kind: static method of Defer
Since: 2.1

Param Type Description
element Node The DOM Node element
[revealedClass] string A CSS class will be added automatically after when an element has been successfully revealed.

Example

// Show single element
var node = document.getElementById('my-video');
Defer.reveal(node);

// Show multiple elements
document.querySelectorAll('.multi-lazy')
  .forEach(function(node) {
    Defer.reveal(node);
  });

// Or even shorter way
document.querySelectorAll('.multi-lazy').forEach(Defer.reveal);

// Add 'loaded' class name after revealed elements
document.querySelectorAll('.multi-lazy')
  .forEach(function(node) {
    Defer.reveal(node, 'loaded');
  });

defer(func, [delay])

Deprecated

Deprecated since version 2.0

Kind: global function
See: Defer
Since: 1.0

Param Type
func function
[delay] number

deferscript(src, [id], [delay], [callback])

Deprecated

Deprecated since version 2.0

Kind: global function
See: js
Since: 1.0

Param Type
src string
[id] string
[delay] number
[callback] callback

deferstyle(src, [id], [delay], [callback])

Deprecated

Deprecated since version 2.0

Kind: global function
See: css
Since: 1.0

Param Type
src string
[id] string
[delay] number
[callback] callback

deferimg([selector], [delay], [revealedClass], [validator], [observeOptions])

Deprecated

Deprecated since version 2.0

Kind: global function
See: dom
Since: 1.0

Param Type
[selector] string
[delay] number
[revealedClass] string
[validator] callback
[observeOptions] object

deferiframe([selector], [delay], [revealedClass], [validator], [observeOptions])

Deprecated

Deprecated since version 2.0

Kind: global function
See: dom
Since: 1.0

Param Type
[selector] string
[delay] number
[revealedClass] string
[validator] callback
[observeOptions] object

Node

The DOM Node interface

Kind: global typedef
See: https://developer.mozilla.org/docs/Web/API/Node


Function

A function is a code snippet that can be called by other code or by itself.

Kind: global typedef
See: https://developer.mozilla.org/docs/Glossary/Function


Closure ⇐ Function

In this library, a closure is a Function that gives you access to a DOM Node element.

Kind: global typedef
Extends: Function
See: https://developer.mozilla.org/docs/Web/JavaScript/Closures

Param Type Description
element Node The DOM Node element

Defer.js for another platforms

PHP library

https://github.com/shinsenter/defer.php/

🚀 A PHP library that focuses on minimizing payload size of HTML document and optimizing processing on the browser when rendering the web page.

Wordpress plugin

https://github.com/shinsenter/defer-wordpress/

⚡️ A native, blazing fast lazy loader. ✅ Legacy browsers support (IE9+). 💯 SEO friendly. 🧩 Lazy load almost anything.

Laravel package

https://github.com/shinsenter/defer-laravel/

🚀 A Laravel package that focuses on minimizing payload size of HTML document and optimizing processing on the browser when rendering the web page.

Support my activities

Donate via Paypal Become a sponsor Become a stargazer Report an issue


From Vietnam 🇻🇳 with love.