My angularjs 1.5 application is running in an MS Dynamics 365 environment inside an iFrame on the actual page.
Anyway, it seems like that angularjs is waiting until all JS-operations from Dynamics, even outside the frame (script-loading etc.), have been finished and only then it's going to bootstrap the actual own app.
That causes many performance loading problems.
I understand that it could (not sure) be in angulars nature to wait for all scripts cause there could be something relevant for it's execution.
But if there are many other not relevant scripts on that page, it causes huge problems.
Is there a way to say "Hey angular! Wait for the scripts "jQuery.js, module1.js" etc." and then you are allowed to bootstrap because thats actually all what you need"?
Just to put the right facts in context, iframes are loaded asynchronously, which means immediately your page is loading it kicks off as well. Now, you can manually control the loading behavior of the iframe by deferring when its loaded into the DOM using a Javascript code that creates the iframe:
function createIframe() {
let iframe = document.createElement("iframe");
iframe.src = "<angularjs-app-url>";
iframe.scrolling = "auto";
iframe.frameborder = "0";
iframe.width = "200px";
iframe.height = "100px";
document.getElementById("div-that-holds-the-iframe").appendChild(iframe);
}
Then you can check if the JS files: jquery.js, module1.js are loaded before calling the createIframe() function:
window.onload = function() {
if (window.jquery && module1){
createIframe();
}
}
Create a script which load the iframe and then add the attribute defer in the call:
<script src="yourscrypt.js" defer></script>
See more in:
https://www.w3schools.com/tags/att_script_defer.asp
Related
I have some javascript that is not required for my initial page load. I need to load it based on some condition that will be evaluated client-side.
$(document).ready(function() {
let someCondition = true; // someCondition is dynamic
if (someCondition) {
var element = document.createElement('script');
element.src = 'https://raw.githubusercontent.com/Useless-Garbage-Institute/useless-garbage/master/index.js';
element.defer = true; // does this make a difference?
element.onload = function() {
// do some library dependent stuff here
document.getElementById("loading").textContent = "Loaded";
};
document.body.appendChild(element);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="loading">Loading...</h1>
Does it make a difference (in terms of how browser will treat the script tag), if a new tag created using javascript, after document is ready, has 'defer' attribute or not? I think there is no difference, but how can I say for sure?
I believe I understand how deferred scripts behave when script tag is part of the initial html (as described here). Also, this question is not about whether element.defer=true can be used or not (subject of this question).
No that doesn't make any difference, the defer attribute is ignored in case of "non-parser-inserted" scripts:
<script defer src="data:text/javascript,console.log('inline defer')"></script>
<script>
const script = document.createElement("script");
script.src = "data:text/javascript,console.log('dynamic defer')";
script.defer = true;
document.body.append(script);
</script>
<!-- force delaying of parsing -->
<script src="https://deelay.me/5000/https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Look at your browser's console or pay attention to the logs timestamps to see that the dynamically inserted script actually did execute while we were waiting for the delayed script to be fetched.
There's a difference between adding them to the function and adding directly the CDN ( especially in your case ).
Let's look at the code execution of the above-mentioned code first,
You have added the jquery CDN first ( without defer ) so that loads first.
$(document).ready will be fired once after the complete load of jquery.
There'll be the creation and insertion of a new script tag to the dom.
Download the https://raw.githubusercontent.com/Useless-Garbage-Institute/useless-garbage/master/index.js asynchronously.
Let's look at another approach: adding CDN to the code:
Your DOM will have 2 script tags.
Both will start loading based on the type of load parallelly ( defer async etc ).
Notice you are not waiting for the dom ready event to load the second script.
I suggest adding only the main JS part in a js file and adding it to the CDN. Others can wait load with the delay.
In case you are really needed with a js src, then don't load it the first way since it waits for the complete page load.
I suggest you read and look at web-vitals and SEO for this.
and for your other question, yes you can add defer attribute with element.defer=true to the elements while creating and loading to DOM.
Hope this answer helps you!
Feel free to comment if you get any errors or doubts.
I think the JQuery Arrive lib will solve your case.
I am dynamically creating iframe , which just contains content (no src attribute).
var iframe = document.createElement('iframe');
iframe.contentWindow.document.body.innerHTML= my_page_content;
....
however, JS scripts (<script src="....." inside my_page_content) are not being loaded and I have to re-load scripts.
these methods wont help me to reload frame:
//this one emptyfies the iframe at all
iframeElement.src = iframeElement.src
//this one is not possible, because the `<script>` links are embedded in the content already.
var script = doc.createElement('script'); script.src = "jquery.min.js";
framebody.appendChild(script);
what are the solutions to force the iframe to load the included scripts in its html content? maybe I am attaching the content in a wrong way?
The only way I've solved this was to write the body inside iframe using write() command:
var ifr = iframeElement.contentWindow.document;
ifr.open(); ifr.write("<body>"+ my_page_content +"</body>"); ifr.close();
neither appendChild() nor .innerHTML helped me.
I have a module that needs to execute a document.write action in order to print a banner once the page is loaded.
If I do this using the old-school way, I get no problems.
The banner is printed inside the div.
<div id="banner">
<script> addAdvert() </script>
</div>
<script>
function addAdvert(){
srcScript = 'http://www.urltoscript.js';
document.write('<script type=\"text/javascript\" src=\"'+srcScript+'" ><\/script>');
}
</script>
But If I try this using a require js module (kind of this):
addAvert: function() {
var srcScript = options.urltoScript
document.write('<script type=\"text/javascript\" src=\"'+srcScript+'" ><\/script>');
}
It executes the document.write and render all the document printing only the banner on the entire document...
I have try this alternative:
addAvert: function() {
var srcScript = options.urltoScript
var bsa = document.createElement('script');
bsa.type = 'text/javascript';
bsa.async = true;
bsa.src = srcScript;
$("#banner").append(bsa);
}
Judging by your comment, the script which you are trying to load from the imaginary URL http://www.urltoscript.js also uses document.write. Either you should change this script to not use document.write or you should abandon the idea of loading it asynchronously, because document.write does not work reliably when invoked asynchronously.
You've already discovered when you tried require([bsa.src]) (as you mentioned in a comment) that you cannot call document.write from a script that is loaded asynchronously. (Also note that just doing require([bsa.src]) is not going to work unless the source code at the other end is an AMD-module or you defined a shim for it.)
Your first attempt at loading through RequireJS did not produce an error message about document.write being loaded asynchronously because the script element that loads it is not itself asynchronous. However, it completely blanked your page. This is because if you call document.write after the page has finished loading, the browser may implicitly call document.open and this may blank your page.
The upshot here is that you cannot reliably use document.write with asynchronous code.
ive installed typekit on my site, the usual two lines of js just after the opening head tag but its extremely slow / unresponsive to load in the fonts, this is completly remedied by refreshing the page, after that the typekit font load in perfectly and really quickly. But from a users point of view they will never know to do that, so they will be served the default fonts.
I have the typekit js as the very first thing under the opening head tag before the metatags and before loading in jquery, jquery-ui and other scripts.
Has any one else had trouble with this ?
what seemed to work for me was to load the script in an asynchronous pattern - as specified on the typekit blog, ive copied it in bellow
Standard asynchronous pattern
This first pattern is the most basic. It’s based on patterns written about by web performance experts like Steve Souders and used in other JavaScript embed codes like Google Analytics.
<script type="text/javascript">
TypekitConfig = {
kitId: 'abc1def'
};
(function() {
var tk = document.createElement('script');
tk.src = '//use.typekit.com/' + TypekitConfig.kitId + '.js';
tk.type = 'text/javascript';
tk.async = 'true';
tk.onload = tk.onreadystatechange = function() {
var rs = this.readyState;
if (rs && rs != 'complete' && rs != 'loaded') return;
try { Typekit.load(TypekitConfig); } catch (e) {}
};
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(tk, s);
})();
</script>
This pattern uses a single inline tag to dynamically add a new script element to the page, which loads the kit without blocking further rendering. An event listener is attached that calls Typekit.load() once the script has finished loading.
How to use it:
Place this snippet at the top of the so the download starts as soon as possible.
Edit the highlighted TypekitConfig object and replace the default with your own Kit ID.
You can add JavaScript font event callbacks to the TypekitConfig object.
Advantages:
Loads the kit asynchronously (doesn’t block further page rendering while it loads).
Disadvantages:
Adds more bytes to your html page than the standard Typekit embed code.
Causes an initial FOUT in all browsers that can’t be controlled or hidden with font events.
I have a photo gallery page hosted on a CMS (Squarespace) which has some of it's own scripts which load the thumbnails asynchronously.
The actual large images however are not preloaded, so I decided to add my own script into the mix to just make the browser load those larger images into the cache in the background, like this:
(function($) {
var cache = [];
// Arguments are image paths relative to the current page.
$.preLoadImages = function() {
var args_len = arguments.length;
for (var i = args_len; i--;) {
var cacheImage = document.createElement('img');
cacheImage.src = arguments[i];
cache.push(cacheImage);
}
}
})(jQuery)
$(window).load(function(){
$.preLoadImages(
"/picture/1.jpg",
"/picture/2.jpg", //etc.
);
});
I placed my code in a $(window).load() because this is a background script and it's not essential it even runs at all, it's just to improve performance.
However, I think this script is somehow blocking the CMS's own thumbnail preloading script.
Am I right? And most importantly, is there a way to dictate that my script only run after all other scripts on the page have run?
cheers
JavaScript is always running, the hover event for example is firing constantly, mousemove, etc...there's no "end" to the script run.
However in your case, this shouldn't block any other preloading...also you can use document.ready here, since you don't actually need images loaded before your code executes.
In fact, you're actually slowing down the page by using window.load instead...since the preloading starts later, when it could be parallelized with other downloads earlier by the browser. Instead use document.ready, like this:
$(function(){
$.preLoadImages(
"/picture/1.jpg",
"/picture/2.jpg", //etc.
);
});
Scripts are loaded top down, and body onloads are normally appended to existing onloads - so as long as that $(function().. is at the end of the page, it'll be ran last. (last (as per nick's comment) meaning the initial parse/run of the document)