I'm currently looking to improve the perception of a web application by ensuring that the company logo is downloaded ahead of the javascript.
To do this I moved the javascript references below the img element for the company logo.
For example:
<img src="/Images/Logo.jpg" alt="My Company"/>
<script type="/Scripts/MyScripts.js"></script>
When looking at Google Chrome Developer Tools I can see that the call for the logo is made however it remains as "pending" until all the javascript on the page has been downloaded.
Why is this happening? How can I ensure that the company logo is loaded ahead of the javascript?
Try to use $(window).load for your scripts if you're using jQuery.
$( window).load(function() {
//put js code here
});
According to the this site :
The window load event executes a bit later when the complete page is
fully loaded, including all frames, objects and images. Therefore
functions which concern images or other page contents should be placed
in the load event for the window or the content tag itself.
As for separate files that you have to add to your site using <script src='path/to/file'>, I recommend using $.getScript.
$.getScript("path/to/file");
Here is the $.getScript manual.
Browser has to download and execute JS files as soon as one occurs during HTML markup parsing (at least due to possible usage of document.write in the scripts).
One of the best solutions would be adding onload event handler which loads your script dynamically when page is ready:
<script type="text/javascript">
window.addEventListener("load",function () {
var elem = document.createElement("script");
element.src = "file.js";
document.body.appendChild(element);
, false);
</script>
Related
We have a website that is supposed to be loading a logo provided by a 3rd party (the logo is a link that allows users to see that our site has been verified by that 3rd party.)
To get this to work, we're told to include a short script in the head
<script type="text/javascript">
//<![CDATA[
var tlJsHost = ((window.location.protocol == "https:") ?
"https://secure.comodo.com/" : "http://www.trustlogo.com/");
document.write(unescape("%3Cscript src='" + tlJsHost +
"trustlogo/javascript/trustlogo.js'
type='text/javascript'%3E%3C/script%3E"));
//]]>
</script>
And another script in the body:
<script language="JavaScript" type="text/javascript">
TrustLogo("https://ourfakesite.com/logo.png", "CL1", "none");
</script>
This all worked fine, initially: the external script is loaded, the function is run, the logo shows up. Perfect.
The problem occurred when the remote site got really slow...all of our pages that load this logo suddenly became very slow as well, since the script is running synchronously.
Ideally, I'd like this to work as if it were designed as an ajax type call...load the page, and after the page is loaded, attempt to load the extra content.
I've tried some combinations of async/defer and using things like ajax, but it seems that because the JS is using a document.write, if the page is fully loaded, the document.write blows away the existing document before writing the new data; the page loads...and then disappears and the logo appears. (I've seen some commentary explaining that this is expected behavior when document.write is used after the page is loaded.)
Is there a way to do this? Is there an alternate path I'm not considering?
Looking at https://secure.comodo.com/trustlogo/javascript/trustlogo.js, the TrustLogo function itself uses document.write (indirectly, the code is minified, but eventually it does), which means you can't use those scripts asynchronously. If you make the first script asynchronous and append that JavaScript file another way, then you have to make the second script asynchronous, and that would mean document.write (within the TrustLogo function) would be called after the main HTML parsing is complete, which in turn means that there'd be an implicit document.open, which would erase your page. :-(
Of course...you could put all of that in an iframe on your main page, so that only the iframe, not your whole page, is impacted. Provided that's not a violation of the terms of use of the logo (obviously, you'd use a relative path for the iframe so their code sees the right domain and such).
Please Help.
Question: Can I dynamically load a JS file (/scripts/banner.js) and then use one of its functions -- writeBanner(document, t1, t2, t3) -- to finish writing the page?
I've read till my eyes bleed, but:
-- Every example I find assumes the reader will call a function AFTER the page is rendered, and
-- Every example assumes blocking is bad.
Unfortunately:
-- I need to call the functions in order to finish writing the page that loaded them, and
-- Blocking is not a problem. The app is deployed as an EAR file, so no JS files need thereafter be downloaded from anywhere else.
Why try to do this?
The initial window ("TAPP") loads a dozen functions from 6 JS files. All pages use them to write HTML in the page's body element that displays a consistent banner with up to 3 paramaterized title lines.
Level-1 Pages: These are opened in the initial ("TAPP") window by each other. It already has all functions loaded – works perfectly.
Level-2 pages: These are opened in pop-up windows opened by level-1 pages. They use "this.opener", i.e. "TAPP" to call those functions – works perfectly.
Now I want to be able to open Level-2 pages both
-- as pop-ups from a level-2 page, AND
-- as free standing pages.
NOTE: All level-2 pages.jsp being with this include to write the HEAD element:
<%# include file='/jsp-pages/level-2/headers/beg.jsp' %>
That way I only need to deal with scripting for all of them, in one place, at one time.
First Step: I added this code to beg.jsp:
<script language="javascript">
var SH = "";
if (this.opener && this.opener.name == "TAPP") {
SH = this.opener; // TAPP has all required functions
} else {
//Dynamically add the required <script> elements
/************************************/
// see code I tried below
/************************************/
SH = this; // "this" now has all the functions TAPP has
// alert ("Opener is NOT TAPP: " + SH);
}
// All pages can now call SH.writeBanner(document, t1,t2, t3) with their own titles
</script>
Here's the rub. When the alert () function above is uncommented BOTH tries (DOM and document.write() below) work perfectly. When it is commented out, level-2 pages opened as pop ups work perfectly BUT when opened as free standing pages do NOT write their titles. Obviously they are being rendered before the script is loaded.
My Tries to date:
-- Give up! Skip the code above. Hard-code six additional tags in "/jsp-pages/level-2/headers/beg.jsp" that will reload the functions in the six JS files every time any level-2 page is opened Either way.
Ugly, inelegant, redundant, a waste if the page is opened as a pop-up, to be avoided at all cost.
-- When TAPP is not this.opener, use DOM to load the JS files by adding script elements at the end of
<script type="text/javascript">
function dynamicload(){
var head = document.getElementsByTagName("head")[0];
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.setAttribute("src", "/scripts/banner.js");
script.async = false; // halt rendering until writeBanner() is loaded?
head.appendChild(script);
//alert ("DL Done");
}
dynamicload();
</script>
-- When TAPP is not this.opener, use document.write() to write the six scripts.
<script type="text/javascript">
document.write('<SCR'+'IPT src="/scripts/banner.js '><\/SCR'+'IPT>');
// and six more like it
</script>
So HELP!
Is it really NOT possible to use dynamically loaded functions to finish writing the page that dynamically loaded them?
glb
You can add things to the current page using dynamically loaded code. But, you cannot use document.write() to do so. You must add DOM elements directly to the page with methods like .appendChild() or .insertBefore() or set .innerHTML on an existing DOM element.
The problem with document.write() is that once the page had been loaded (and thus the document stream closed), any future calls to document.write() will clear the current page and start writing to a new, blank page which general ruins what you are trying to do.
And, when you dynamically load code, it will load AFTER the current document has finished loading.
document.write() is intended to insert content at the current location in the document stream while the document is in the process of loading which only works when the script is present in the original HTML either as a <script> tag or it can be used on a brand new document (such as the creation of a new iframe or new window).
Simple answer. You can't.
A page cannot load JS files with functions it needs to write the rest of the page.
No matter how you script to load the JS files -- add a script element with DOM, or write it in with document.write() -- the JS files end up being loaded AFTER the page is loaded when it is too late to write the page. (See discussion with nothingnecessarey.)
However, it still bothers me that if I throw an alert() in my the script, both conditional approaches work – DOM and document.write() -- i.e. I had titles! All I can think of is the alert causes the page to re-render itself and since the alert is called after the page is loaded, the JS files are loaded.
Thanks to all for their help
AFTERTHOUGHT: I dreamed that opening an empty page with an iFrame to load my level-2 might work. If so I'll return. If not ... I give up.
I have a problem using processing.js across multiple pages.
I have a master page (test.html) which loads, via jquery, all pages into a div named "contentarea". This is just an exerpt of "test.html", just so you get the idea:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script src="js/processing.js"></script>
<script>
$(document).ready(function(){$("#contentarea").load("page1.html");
etc...
</script>
<div id="contentarea">...</div>
As you can see the Test.html contains the processing reference "src="js/processing.js"" and will intercept any static "canvas data-processing-sources" on its own page ("test.html" - only).
When page1.html is loaded into test.html, processing.js does not initialise the canvas. But when viewing the page (page1.html) on its own, processing.js intercepts "canvas data-processing-sources" and loads fine.
Here is a working example of the problem:
EXAMPLE
http://78revelationscom.ipage.com/site/test/test.html
QUESTION:
How can I get processing.js to initialise (or re-initialise, or refresh, or load) a canvas that is dynamically loaded?
Thank you in advance!
This might still be a problem since it won't be solved in the library until the next version: For now, the solution is to not rely on Processing auto-loading, since that only happens on DOMContentLoaded events. Instead, when you change page content you can grab the canvas's data-processing-sources attribute and create a new Processing instance from the indicated source code:
function loadSketchOnContentSwap() {
var canvas = /* get the relevant canvas however you want */
var sources = canvas.getAttribute("data-processing-sources").split(/\s+/);
Processing.loadSketchFromSources(canvas, sources);
}
I was on jsfiddle.net recently and I saw this as a configuration option. This got me to thinking that it might help a problem I'm having as such:
I load multiple images (haven't upgraded to a single sprite yet) so that I can not use my controls until they are all downloaded...the images take most of the download time so that for the first few seconds I can not access my controls.
Currently I'm using one of these two..both work.
window.onload = initialize_page
window.addEventListener('load',initialize_page);
Related
Jquery document ready vs. window.onload
window.onload vs. body.onload vs. document.onready
window.onload vs <body onload=""/>
AFAIK onDomReady() fires once the DOM has loaded. If the page contains external sources, such as images, then it may fire before these have finished loading.
onLoad() fires after the whole page has finished loading, including external sources.
So it's possible for onDomReady() to fire before onLoad() but you'll have to test it on your page.
My friend read an article which mentioned that moving all JavaScript files to the end of the closing body tag (</body>), will improve the performance of a web page.
I have moved all JS files to the end except the JQuery and the JS files which are attaching event to an element on page, like below;
$(document).ready(function(){
//submit data
$("#create_video").click(function(){ //... });
});
but he's saying to move the jQuery library file to the end of body tag.
I don't think it is possible, because I am attaching many events to page elements on load using jQuery selectors, and to use jQuery selectors it is must to load jQuery library first.
Is it possible to move JQuery library file to the end of page right before closing body tag (</body>) ??
Thanks
It's standard practice to move all your js includes to the bottom of your page. This is because when a browser loads script, it does not spawn a new thread to do so, so basically the browser will wait until it has loaded the script before it proceeds to the next line.
What this means for your users is that they will see a blank screen. Much better to have them see the full(ish) page as then it doesn't look like it has stalled.
The $(document).ready function says not to run until the DOM has finished being instantiated - so moving it to after body is okay so long as the JQuery library is loaded first. Unconventional and some assumptions may not be correct anymore but okay.
Just take in account that the jQuery JavaScript file must be loaded before any call to the $(...) function.
Use a "Dom Ready Queue" to collect functions to be executed once jQuery is loaded and the DOM is ready.
Example:
<html>
<head>
<script type="text/javascript">
var domReadyQueue = [];
</script>
</head>
<body>
...
<div class="foo"></div>
<script type="text/javascript">
domReadyQueue.push(function($){
$('.foo').doSomething();
})
</script>
...
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script type="text/javascript">
jQuery(function(){
while (domReadyQueue.length) {
domReadyQueue.shift()(jQuery);
}
});
</script>
</body>
</html>
The reason that article asked you to move scripts to the bottom, is to allow other artifacts to get downloaded first. (css & images, which will speed up apparent rendering times)
This is because HTTP 1.1 recommends only downloading 2 items per hostname. And you would definitely want your css file to be one of the first files downloaded, rather than javascript which could make the site appear to render slower (just by the fact that the browser hasn't got the css file yet and isn't sure what it should do with the html)
But if you used google to host your jQuery then that would download in parallel and negates any reason for moving it to the bottom of your pages.
Alternatively, you could set up a second hostname to host static content (such as css/scripts/images).
But google have already done the hard work for you, so it makes sense to use it if it suits. :-)
Q - Why do I often see JavaScript
written/included before the closing
body element in an (x)HTML document?
A - DOM elements can not be accessed
by JavaScript until the browser has
loaded the HTML elements into the DOM.
By placing JavaScript at the end of an
(x)HTML document (before the closing
body element), you will ensure that
the script is called as soon as the
DOM is constructed/loaded and ready
for manipulation. An advantage of this
approach is that JavaScript code is
executed right after the DOM is
constructed and possibly before the
onload event would fire.
JavaScript beginners get tripped up by
this constantly by placing code that
manipulates the DOM in the header
element of an (x)HTML document. This
causes an error because the DOM has
not yet been constructed and thus is
not yet accessible to JavaScript that
traverses/manipulates the DOM.
From JavaScript Execution & Onload Techniques in Web Browsers
Use unobtrusive javascript (adding event listeners to elements instead of onclik ="..." etc).
Put all your .js files at the bottom of the body tag, with the main library (jQuery in this case) placed first, and everything will be fine. You can use a bundler like bundle fu
You will see a big performance boost of loading your page.