Javascript dependencies are inherently blocking resources, more precisely parser blocking . Parser blocking means that when the browser parser starts reading the HTML code and encounters a script, it suspends all reading and rendering operations in order to execute the code. An HTML page usually has more JS dependency, these continuous interruptions can considerably slow down the loading and rendering speed of the page itself. Furthermore, if the script is external to the website, the deadlock will be extended by the download times of the resource.
Several techniques can be used to reduce rendering blocks caused by Javascript, including using the HTML async and defer attributes. But what is the difference between async and defer? In what context should one be used instead of the other?
Index:
- Render-Blocking JavaScript
- <script>
- <async script>
- <script defer>
- asinc and defer together
- Which attribute is best to use?
- How to asynchronously invoke JavaScript dependencies in WordPress
- How to implement async and defer on a specific JavaScript dependency
- How to implement async and defer across multiple JavaScript dependencies
- Some known handles
Differences between standard, async and defer
Render-Blocking JavaScript
Is JavaScript rendering-blocking a term that doesn’t sound new to you? Do you always see it on your Google PageSpeed Insights or GTmetrix reports ?
JavaScript dependencies present in your HTML can delay the display of page content because the browser must first download and interpret them.
The problem of “Render-blocking” derives from a default behavior of the web browser: it wants to receive and completely process everything that is indicated in the HTML head before starting the rendering of the page. In other words, the presence of external files in JavaScript blocks the browser’s fundamental function: designing the page. The result can be a slow site and frustrated users.
With the async and defer attributes you can solve this problem by removing or delaying the lock.
The HTML <script src = ”script.js”> </script> element allows you to define when the browser should start executing the JavaScript code on your page. The async and defer attributes were added to the WebKit in September 2010 .
The async and defer attributes for script elements are useful for optimizing page loading by avoiding HTML page rendering stops caused by blocking elements such as JavaScript dependencies .
<script>
Let’s start by defining what happens when you invoke a <script> without any attributes. The HTML file is parsed until a dependency (a <script>) is called, at which point the parsing stops and the browser starts downloading the file (if it is external). The <script> will be executed immediately after the download, the HTML rendering will continue only after the <script> is executed. For slow and heavy servers, calling <script> in this way means that the display of the web page will be slowed down.
<async script>
- The async attribute avoids interrupting HTML rendering during the <script> download, which actually happens in parallel
- The <script> is executed immediately after the download
- Page parsing is paused only while the <script> is being executed
Don’t care when the <script> is available? async is the better of the two methods: HTML parsing can continue and the <script> will be executed as soon as it is ready. I recommend this for <scripts> like Google Analytics.
<script defer>
- The defer attribute avoids interrupting the rendering of the HTML during the download of the <script>, which actually takes place in parallel
- The <script> is executed immediately after parsing the HTML page
- Page parsing is never paused
A positive effect of this attribute is that the DOM (Document Object Model: natively supported by browsers to modify elements of an HTML document, DOM is a way to dynamically access and update the content, structure and style of documents) will already ready for the <script>.
asinc and defer together
Can both attributes be used together? According to the standard, yes it is possible .
I quote the original text:
The defer attribute may be specified even if the async attribute is specified, to cause legacy Web browsers that only support defer (and not async) to fall back to the defer behavior instead of the synchronous blocking behavior that is the default.
Which translated means: The defer attribute can also be specified in the presence of the async attribute, to allow legacy (dated) browsers that only support defer (and not async) to postpone the download and execution of the JS instead of following the behavior synchronous blocking default.
Which attribute is best to use?
Generally you want to use async wherever possible as a second choice defer and finally no attributes . Here are some general rules to follow:
- If the <script> is modular and does not rely on other <scripts>, it would be better to use async
- If the <script> is based on other <script> or is invoked by another <script>, it would be better to use defer
- If the <script> is small and is invoked by an asynchronous <script>, it would be better to use an inline <script> without attributes placed above the asynchronous <script>
Usually the jQuery library is not a good candidate for the async attribute because other <scripts> might depend on that (heavily used) library. You can use async but you need to make sure the other <scripts> don’t run until jQuery loads.
Add Defer & Async attributes to WordPress scripts
To apply the async attribute to the JavaScript dependencies of a WordPress site you can use this function to insert in your theme’s functions.php file.
Until now, WordPress developers did not have the ability to insert scripts optimally for the simple fact that WordPress did not have a dedicated filter for adding the async and defer attributes .
Fortunately, this is no longer the case. Since version 4.1 of WordPress, a new filter has been introduced which offers a solution to add async and defer attributes to JavaScript dependencies.
How to implement async and defer on a specific JavaScript dependency
Let’s first see how to apply the async or defer attribute to a single script whose handle we know (the name with which to call the dependency for example in a function).
First of all you need to navigate to the functions.php file or equivalent if you use a custom add-on. Copy and paste the script below making the appropriate changes.
- my-js-handle : Replace this example handle with the name of the script you need to optimize
- async or defer? : replace in line 4 async = ”async” with defer = ”defer” to change attribute
Parameters 10, 2 respectively indicate the execution priority of the filter and the number of arguments passed to the filter function.
How to implement async and defer across multiple JavaScript dependencies
To implement async or defer to multiple scripts at the same time just use an array and a foreach . Enter in line 3 all the handles you want to manage within the array, at the bottom of the page you will find the list of standard handles used by WordPress.
Navigate to the functions.php file or equivalent if you use a custom add-on. Copy and paste the script below making the appropriate changes.
- $ scripts_to_defer = array (‘…’, ‘…’); : Enter all script handles you want to optimize as shown in the example
- async or defer? : replace in line 7 defer = ”defer” with async = ”async” to change The result of this function is the following: defer attribute hanging on all dependencies that I have set.
Some known handles
On my site (which uses the Genesis framework ) I have optimized all the scripts whose loading can be delayed without impacting the functionality of the pages and other scripts. For example jQuery can’t delay it otherwise other scripts like superfish , which depends on jQuery, don’t get activated properly and chrome console shows error.
Here are some more well-known handles that you can use in the functions shown in this guide. Check if they are present in your HTML code and use them in the proposed functions.
Predefined scripts included and registered by WordPress :
- Script name – Handle
- Image Cropper – Image cropper (not used in core, see jcrop)
- Jcrop – jcrop
- SWFObject – swfobject
- SWFUpload – swfupload
- SWFUpload Degrade – swfupload-degrade
- SWFUpload Queue – swfupload-queue
- SWFUpload Handlers – swfupload-handlers
- jQuery – jquery
- jQuery Form – jquery-form
- jQuery Color – jquery-color
- jQuery Masonry – jquery-masonry
- Masonry (native Javascript) – masonry
- jQuery UI Core – jquery-ui-core
- jQuery UI Widget – jquery-ui-widget
- jQuery UI Accordion – jquery-ui-accordion
- jQuery UI Autocomplete – jquery-ui-autocomplete
- jQuery UI Button – jquery-ui-button
- jQuery UI Datepicker – jquery-ui-datepicker
- jQuery UI Dialog – jquery-ui-dialog
- jQuery UI Draggable – jquery-ui-draggable
- jQuery UI Droppable – jquery-ui-droppable
- jQuery UI Menu – jquery-ui-menu
- jQuery UI Mouse – jquery-ui-mouse
- jQuery UI Position – jquery-ui-position
- jQuery UI Progressbar – jquery-ui-progressbar
- jQuery UI Selectable – jquery-ui-selectable
- jQuery UI Resizable – jquery-ui-resizable
- jQuery UI Selectmenu – jquery-ui-selectmenu
- jQuery UI Sortable – jquery-ui-sortable
- jQuery UI Slider – jquery-ui-slider
- jQuery UI Spinner – jquery-ui-spinner
- jQuery UI Tooltips – jquery-ui-tooltip
- jQuery UI Tabs – jquery-ui-tabs
- jQuery UI Effects – jquery-effects-core
- jQuery UI Effects – Blind – jquery-effects-blind
- jQuery UI Effects – Bounce – jquery-effects-bounce
- jQuery UI Effects – Clip – jquery-effects-clip
- jQuery UI Effects – Drop – jquery-effects-drop
- jQuery UI Effects – Explode – jquery-effects-explode
- jQuery UI Effects – Fade – jquery-effects-fade
- jQuery UI Effects – Fold – jquery-effects-fold
- jQuery UI Effects – Highlight – jquery-effects-highlight
- jQuery UI Effects – Pulsate – jquery-effects-pulsate
- jQuery UI Effects – Scale – jquery-effects-scale
- jQuery UI Effects – Shake – jquery-effects-shake
- jQuery UI Effects – Slide – jquery-effects-slide
- jQuery UI Effects – Transfer – jquery-effects-transfer
- MediaElement.js (WP 3.6+) – wp-mediaelement
- jQuery Schedule – schedule
- jQuery Suggest – suggest
- ThickBox – thickbox
- jQuery HoverIntent – hoverIntent
- jQuery Hotkeys – jquery-hotkeys
- Simple AJAX Code-Kit – sack
- QuickTags – quicktags
- Iris (Color picker) – iris
- Farbtastic (deprecated) – farbtastic
- ColorPicker (deprecated) – colorpicker
- Tiny MCE – tiny_mce
- Autosave – autosave
- WordPress AJAX Response – wp-ajax-response
- List Manipulation – wp-lists
- WP Common – common
- WP Editor – editorremov
- WP Editor Functions – editor-functions
- AJAX Cat – ajaxcat
- Admin Categories – admin-categories
- Admin Tags – admin-tags
- Admin custom fields – admin-custom-fields
- Password Strength Meter – password-strength-meter
- Admin Comments – admin-comments
- Admin Users – admin-users
- Admin Forms – admin-forms
- XFN – xfn
- Upload – upload
- PostBox – postbox
- Slug – slug
- Post – post
- Page – page
- Link – link
- Comment – comment
- Threaded Comments – comment-reply
- Admin Gallery – admin-gallery
- Media Upload – media-upload
- Admin widgets – admin-widgets
- Word Count – word-count
- Theme Preview – theme-preview
- JSON for JS – json2
- Plupload Core – plupload
- Plupload All Runtimes – plupload-all
- Plupload HTML4 – plupload-html4
- Plupload HTML5 – plupload-html5
- Plupload Flash – plupload-flash
- Plupload Silverlight – plupload-silverlight
- Underscore js – underscore
- Backbone js – backbone
- imagesLoaded – imagesloaded
- Scriptaculous Root – scriptaculous-root
- Scriptaculous Builder – scriptaculous-builder
- Scriptaculous Drag & Drop – scriptaculous-dragdrop
- Scriptaculous Effects – scriptaculous-effects
- Scriptaculous Slider – scriptaculous-slider
- Scriptaculous Sound – scriptaculous-sound
- Scriptaculous Controls – scriptaculous-controls
- Scriptaculous – scriptaculous
- Prototype Framework – prototype
Let me know in the comments if you managed to postpone the loading of your JavaScript and how this change impacted the loading times. Soon