DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • The SPACE Framework for Developer Productivity
  • Unlocking the Power of AIOps: Enhancing DevOps With Intelligent Automation for Optimized IT Operations
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline
  • Top 10 Pillars of Zero Trust Networks

Trending

  • The SPACE Framework for Developer Productivity
  • Unlocking the Power of AIOps: Enhancing DevOps With Intelligent Automation for Optimized IT Operations
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline
  • Top 10 Pillars of Zero Trust Networks
  1. DZone
  2. Coding
  3. JavaScript
  4. Lazy Loading Asyncronous Javascript

Lazy Loading Asyncronous Javascript

Emil Stenström user avatar by
Emil Stenström
·
May. 10, 10 · News
Like (0)
Save
Tweet
Share
16.46K Views

Join the DZone community and get the full member experience.

Join For Free

Like many of you might know, I’m working on a site called Kundo with a couple of friends. It’s kinda like a Swedish version of Getsatisfaction, which means we have a javascript snippet that people add to their site to get feedback functionality. Cut-and-paste instead of writing the code yourself. Simple.

The problem is, how do you load an external javascript with minimal impact on your customer’s sites? Here are my requirements:

  1. Small. I don’t want a big mess for them to include on their sites. 10-15 lines, tops.
  2. Stand-alone. The environment is unknown, so we can’t rely on any external dependencies, like javascript libraries.
  3. Cross-browser. I have no idea what browsers me customer’s customers have, so I can’t do anything modern or fancy that isn’t backwards compatible. I assume at least IE6 and up though.
  4. Asynchronous download. The download of my script should not block the download of any script on their sites.
  5. Lazy Loading. If my site is temporarily slow, I don’t want to block the onload event from triggering until after our site responds.
  6. Preserve events. Any events used should not override any events on the customer’s site. Minimal impact, like I said.
  7. Don’t pollute namespace. Global variables should be avoided, since they could conflict with existing javascript.

Note: I did not make all of this up myself. Lots of people did, I’m just writing it down for you. Thanks: Jonatan, Steven, Peter, and Linus.

Script tag

<script type="http://yourdomain.com/script.js"></script>
While being the stand-alone, cross-browser, and the shortest piece of code possible; it doesn’t download asynchronously and doesn’t lazy load. Fail.



Screenshot from Firebug’s net console: The script (set to load in 2 seconds) blocks the download of the big image (added after the above script tag, and used throughout this article as a test). Onload event (the red line) triggers after 2.46 seconds.

Async pattern (A script tag written with javascript)

Steve Souders, the web performance guru, has compiled a decision tree over different ways to achieve non-blocking downloads. Have a look at that graph.

Since we’re on a different domain, and only have one script (order doesn’t matter), the solution is given: We should create a script tag with inline javascript, and append it to the document. Voila! Non-blocking download!

(function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://yourdomain.com/script.js';
x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();

Note: async is a HTML5 attribute, doing exactly what we’re trying to simulate with our hack, so it’s added for good measure. Also, wrapping the code in an anonymous function prevents any variables to leak out to the rest of the document.

This is a pattern that is getting more and more popular nowadays, especially since Google Analytics uses it. But there’s an important distinction here: The above snipped blocks onload from triggering until the referenced script is fully loaded. Fail.


Screenshot from Firebug’s net console: The script (set to load in 2 seconds) downloads in parallell with the big image. Onload event (the red line) triggers after 2.02 seconds.

Lazy load pattern (Async pattern triggered onload)

So, how to you make sure you don’t block onload? Well, you wrap your code inside a function that’s called on load. When the onload event triggers, you know you haven’t blocked it.

window.onload = function() {
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://yourdomain.com/script.js';
x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}

This works, but it overrides the onload event of the site that uses the script. This could be OK in some cases, where you have control over the site referencing the script, but I need to cater for that. Fail.

Unobtrusive lazy load pattern

The logical solution to the above problem is to use an incarnation of addEvent. addEvent is simply a common name for an cross browser way to take the current function tied to onload, add it to a queue, add your function to the queue, and tie the queue to the onload event. So which version of addEvent should we use?

There’s been competitions for writing a short and compact version of addEvent, and the winner of that competition was John Resig, with this little beauty:

function addEvent(obj, type, fn)  {
if (obj.attachEvent) {
obj['e'+type+fn] = fn;
obj[type+fn] = function(){obj['e'+type+fn](window.event);}
obj.attachEvent('on'+type, obj[type+fn]);
} else
obj.addEventListener(type, fn, false);
}

Note: This is unsafe code, since it relies on serializing a function to a string, something that Opera mobile browsers have disabled.

Thing is, we don’t need all that generic event stuff, we’re only dealing with onload here. So if we first replace the type attribute with hardcoded ‘load’, replace obj with ‘window’, and remove the fix for making ‘this’ work in IE, we’ve got four lines of code left. Let’s combine this with the above lazy load pattern:

(function() {
function async_load(){
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = 'http://yourdomain.com/script.js';
x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
}
if (window.attachEvent)
window.attachEvent('onload', async_load);
else
window.addEventListener('load', async_load, false);
})();
This is exactly what we’re looking for here. Finally!


Screenshot from Firebug’s net console: The script (set to load in 2 seconds) downloads after the onload event has triggered. Onload event (the red line) triggers after 0.41 seconds.

And that wraps up this article: Different tactics works for different scenarios, and only understanding them all makes you capable of picking the right one for your problem. As always, I’m waiting for your feedback in the comments. Thanks for reading!

JavaScript Lazy loading Event Download code style

Published at DZone with permission of Emil Stenström. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • The SPACE Framework for Developer Productivity
  • Unlocking the Power of AIOps: Enhancing DevOps With Intelligent Automation for Optimized IT Operations
  • Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline
  • Top 10 Pillars of Zero Trust Networks

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: