Loading jQuery if not loaded - failed approach - javascript

This is what I have in :
<script src="myscript.js" type="text/javascript"></script>
<script type="text/javascript">testfunction("hello");</script>
Inside myscript.js:
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.src = 'jquery-1.9.0.min.js';
document.getElementsByTagName('head')[0].appendChild(script);
}
function testfunction(str) {
$(document).ready(function () {
alert(str);
});
}
Of course jQuery is not needed for the current testfunction, but it will be needed. Using this approach, jQuery is downloaded but NOT loaded to the browser when calling to testfunction() (Uncaught ReferenceError: $ is not defined).
What I could do is to load jQuery in a different script before my JS is loaded. In that case, it will work, but I would have three different scripts and that seems to be not elegant in my honest opinion.
Is there any other way to achieve this?
Thanks!

You might want to try looking at this answer. It may not be waiting until jQuery is fully loaded.

With your code, the script will be loaded asynchronously. You need to add to the script tag an onload event that will trigger the parts that are dependent on jQuery.
If you want the script to be loaded in a synchronous way, use document.write:
window.jQuery||document.write(unescape("%3Cscript src='"+jQueryURL+"' type='text/javascript'%3E%3C/script%3E"));
The document.write technique is very common, just keep in mind that you cannot use it after your document has loaded (or else it will overwrite the whole page).
If you want to use dynamic loading on a larger scale, look at existing loader or AMD libraries.

Related

Load Multiple js file after page load

I have multiple JavaScript files which are loaded before page load which are affecting page speed. I want that my JS files to load after page load though to improve page speed.
I tried to use async and defer but due to dependency to each other, this way is not working out for me. I also tried lazy loading through AJAX but that is also not working for me (using this link https://w3bits.com/async-javascript)
#section Scripts {
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=API_KEY&sensor=false&libraries=places"></script>
<script src="/lib/bootstrap-datetimepicker/js/moment.js" type="text/javascript"></script>
<script src="/lib/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js" type="text/javascript"></script>
<script src="/js/viewcomponent/windowsignup.js"></script>
<script type='text/javascript' src='/js/viewcomponent/kundliregistrationwindow.js' async='async'></script>
}
I use multiple JS files on a page and I want them all to load after page load. Is there any way to do that?
You can use getScript inside document.ready.
$(document).ready(function() {
$.getScript("domainpath/lib/bootstrap-datetimepicker/js/moment.js");
});
It's fetch your js after dom ready.
You can use Jquery's $.getScript() function but then you have to keep an eye on proper loading order. Would recommend more to bundle all necessary files on the server side and only serve a single file
When the browser receives a request for an HTML file the DOM starts to draw. If you place your scripts in the <head> tag the DOM stops from rendering and the browser starts to execute the <script> files.
One solution could be to place your <script> files at the end of the <body>.
Another solution could be to dynamically load your scripts into your page after the page is loaded like this:
window.addEventListener('load', () => {
let script = document.createElement('script');
script.src = './my_lazy_loaded_script.js';
document.body.appendChild(script);
});
If you have multiple files that are dependent on each other you could do something like this using the async/await mechanism:
window.addEventListener('load', async () => {
console.log('page loaded')
try{
await loadFileAsync('./my_first_lazy_load.js');
await loadFileAsync('./my_second_lazy_load.js');
} catch(err){
console.log(err);
} finally {
console.log('Everything loaded')
}
})
const loadFileAsync = (url) => {
return new Promise((resolve, reject) => {
if(url){
let script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
resolve(true);
} else {
reject(false);
}
});
}
If you want to load your scripts as soon as the DOM is rendered, you can replace window.addEventListener('load',()=>{}) with document.addEventListener('DOMContentLoaded', () => {})
You usually use a Scripts section to control the location where your scripts are being rendered in the document. The way browsers work, they will interpret the HTML from top to bottom. If they encounter a <script> tag, they will pause the HTML rendering and interpret the JavaScript first. For external JavaScript files this means that they will be included and interpreted first (if they aren’t marked as defer or async).
As such, a common practice is to add JavaScript at the end of the <body> tag. That way, the scripts will not prevent rendering the document first but they will also execute early enough to be able to immediately have an effect. In addition, since they are executed after the majority of the <body> has already been interpreted, they can directly access DOM elements. So you generally don’t need to listen to another DOM event first before you can do something with the DOM.
For example, this would work just fine:
<body>
<div id="foo"></div>
<script>
var foo = document.getElementById('foo');
</script>
</body>
However, if you had the <script> before the <div> (or inside of the <head>), the script would fail to find the foo element simply because it isn’t added to the DOM yet.
For ASP.NET Core this means that you should make sure that your Scripts section is added at the end of your <body> tag inside your layouts file. So it should look like this:
<!-- (The rest of the layout) -->
#RenderSection("Scripts", required: false)
</body>
</html>
You can also add script tags before the RenderSection call to make sure that those scripts are available on all pages but loaded before other scripts. For example, if you are using Bootstrap and you want to use jQuery, it might make sense to include that globally for all pages. But since you have it before the other scripts, it is available for the other scripts.
As far as dependencies between scripts go, make sure that you include the scripts in the order they need to executed. So if you have script B that depends on functions in script A, make sure to include A before B. But then, without using defer or async, just including them should work just fine.

Intercepting script load

What I need is to hook/intercept other external JS load.
I can place js anywhere in document
Example:
<script src="hook.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
Hook.js should intercept a.js and b.js. Problem is, that when hook.js is executed, i cannot see other scripts (document.scripts contains only hook.js) and document ready event is too late (scripts a.js and b.js are executed).
Is there any way to "see" other script tags, before are executed ?
Thanks for any help
Edit
I need to do any "magic" inside hook.js without modyfing (statically) other HTML.
No jQuery
Credit goes here: https://stackoverflow.com/a/59424277/2016831
You can use a MutationObserver to see what elements are being added to the DOM, and when they are being added, simply change the source code, or if its referencing another URL, just redirect it to your own server, with the original URL as a get parameter instead, and return the modified code that way.
Based on the above answer, you could do something like this:
<script>
new MutationObserver((m, o) => {
let potentialScript = document.querySelector("script + script");
console.log(potentialScript.textContent);
if(potentialScript) {
o.disconnect();
potentialScript
.textContent =
potentialScript
.textContent
.replace(
"})()",
`
window.wow = mySecretMethod;
})()
`
);
}
}).observe(
document.body,
{
childList:1
}
);
</script>
<script>
(function() {
let mySecretMethod = () => {
//does a bunch of evil secret stuff
console.log("HA!");
};
})();
wow()
</script>
<script>
console.log(wow())
</script>
Alternatively you can redirect the HTTP requests with a chrome extension, see https://stackoverflow.com/a/61202516/2016831 for more
If I understand what you're trying to do correctly...
If you can control how scripts A and B are loaded, the best approach is to place them on the same domain as the current page (possibly via proxy), load the files via AJAX, and insert your hooks that way. A library like jQuery as m.casey suggested would make the details of the AJAX and executing the script quite simple.
Otherwise, Javascript does not really have the ability to interact with the parsing of the document (which is what is causing scripts a and b to be loaded in your example, and what would be need to be modified to "intercept" script loading), except by using the evil of document.write to modify the HTML stream. Of course, this only works if hook.js is loaded synchronously (as it is in your example code), if it's loaded into HTML and not XHTML, if you can place a second hook afterwards to postprocess the modified HTML stream, and if you are sure the HTML stream won't escape your mechanism.
For example..
<script id="hook1">document.write("<"+"textarea id='capture'>");</script>
<script src="a.js"></script>
<script src="b.js"></script>
<script id="hook2">document.write("<"+"/textarea");</script>
<script id="hook3">doSomethingWith(document.getElementById("capture").value)</script>
Note that this is a huge hack and you probably shouldn't be doing it.
If you're using jQuery, you could have hook.js load the scripts you wish to intercept as follows:
$.getScript("a.js");
$.getScript("b.js");
This would dynamically create the script tags and you would be certain that hook.js would always proceed a.js and b.js.

Place 'script' before the end of BODY tags with jQuery

This is the 'script' I want before the 'body' tag:
<script type="text/javascript">
var vglnk = { api_url: '//api.viglink.com/api',
key: '89dcd0a12ff35d227eaaaff82503030b' };
(function(d, t) {
var s = d.createElement(t); s.type = 'text/javascript'; s.async = true;
s.src = ('https:' == document.location.protocol ? vglnk.api_url :
'//cdn.viglink.com/api') + '/vglnk.js';
var r = d.getElementsByTagName(t)[0]; r.parentNode.insertBefore(s, r);
}(document, 'script'));
</script>
I want this code to be where I've put "HERE"
<html>
<head>
</head>
<body>
Some HTML and stuff
HERE
</body>
</html>
How would I go about this in jQuery?
(I'm doing this from an extension. Mainly in Chrome, but also Firefox and Internet Explorer.)
You need the content script to do the insert on every page you want.
The code of the content script is really simple and doesn't need jQuery.
var code = "your script code here";
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.appendChild(document.createTextNode(code));
document.body.appendChild(script);
As it will only be called once you don't even need to define a function. You can debug the code using debugger on any web the content script is attaching (F12) you will see your code in the content script tab.
I had the same issue regarding the best place to add jQuery: to the header or before the body tag? The answer is that it does not matter.
The whole page (or DOM) needs to initialize or load in order to accomplish what you are doing.
And...
The more information within the body, the more reliance you need to make sure the document is loaded.
The two sentences above are redundant because:
All jQuery UI, basic syntax, widgets, etc. are triggered with:
$(document).ready( function() {
$("#some_id").click( function {
More code here
});
});`
The code above means that the the full HTML page (or 'document') needs to be loaded before jQuery can run, AKA initialized.
There is an order that jQuery needs to be loaded for a UI to work. The actual library needs to be first, then the UI. The library can be downloaded from jquery.com and uploaded to the designers web space or through a CDN (content display network) to save on bandwidth. Here is an example of how the order should be:
<script src="http://code.jquery.com/jquery-1.6.4.min.js"></script>
<script src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
Notice the library is the first line, and then the UI. In this case I loaded jQuery Mobile.
In conclusion, it does not matter. It is a preference mostly. More in on Unclear where $(document).ready goes.

How to load a Javascript file within another Javascript file and execute file 2 before file 1?

I have written a jQuery plugin, say jquery.plugin.js. I want to use this plugin on a large number of sites.
What I want to do is to write a piece of js code at the top of jquery.plugin.js which will load the jquery.main.js and execute it so that $ is available to be used in jquery.plugin.js.
Thanks.
What you probably want to do is create a new tag in js
script = document.createElement('script');
script.src = 'URL-TO-JQUERY';
And then append that element before the first tag.
document.body.insertBefore(document.getElementsByTagName('script')[0], script);
This will most probably work as the script is inserted before any other js. (except in the head)
Yes, just a interval that checks if jQuery exists:
interval = setInterval(check, 100);
function check(){
if($.version){
// Exec script
}
}
This page may be useful for you
http://code.google.com/p/jquery-ajaxq/
with this script you can use files sequentially
Works only if jQuery is loaded already,
$.when($.getScript("path_to_script")).then(function() {
alert("loaded");
})​
Fiddle - http://jsfiddle.net/fLuDd/
Edit
var fileref = document.createElement('script')
fileref.setAttribute("type", "text/javascript")
fileref.setAttribute("src", 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js')
document.getElementsByTagName("head")[0].appendChild(fileref)
var t = setInterval(function() {
if (typeof(jQuery) == 'function') {
alert("jquery loaded");
clearInterval(t);
}
}, 2000);​
Fiddle - http://jsfiddle.net/fLuDd/1/
Just include the jquery.main.js above the jquery.plugin.js. It should work if you place the script tags in this order.
<script src="jquery.main.js"></script>
<script src="jquery.plugin.js"></script>
If you do not have full control over the html or if jQuery might be loaded from other places also, do this to check if it is loaded or not, and load only if needed.
Load from google
if (typeof jQuery == 'undefined') {
document.write('<script type="text/javascript" src="http://www.google.com/jsapi"></script>');
document.write('<script type="text/javascript">');
google.load("jquery", "1.4.2");
document.write('</script>');
}
Load from same server
if (typeof jQuery == 'undefined') {
document.write('<script type="text/javascript" src="path/to/jquery.min.js"></script>');
}
There are some AMD packages that do what you want, like requirejs, but... you'll have to load them first!
You could use a polling technique (load jQuery dynamically and poll until $ exists), not very elegant or efficient.
You could also attach an onload event handler to the dynamic jQuery script, which will trigger your plugin after loading jQuery. Of course such event handlers have cross-browser compatibility issues, so it's easier to write them... with jQuery.
Bottom line: it's a lot of trouble and you're usually better off just writing two script tags.
P.S.: Some of the above techniques are explained in this article:
http://www.stevesouders.com/blog/2008/12/27/coupling-async-scripts/

How to lazy-load jQuery itself, specially when $(document).ready() is being used

I use jQuery on my website like this:
<head>
<script src="http://ajax.googleapis.com/.../jquery.min.js" ...></script>
</head>
I then use:
$(document).ready(function(){
});
On some occasions, this event is used:
$(document).ready(function(){
var s = document.createElement("script");
s.type = "text/javascript";
s.async = true;
s.src = "http://www.script-host.com/.../script.js";
document.getElementsByTagName("head")[0].appendChild(s);
});
Now jquery.js seems to be (one of) the heaviest resource on my website in terms of filesize. I therefore want to lazy load jquery.js itself but I understand that this would cause all document.ready events to fail. What is the best workaround for this?
Maybe this recent article may help you: http://samsaffron.com/archive/2012/02/17/stop-paying-your-jquery-tax
the idea behind is to create a temporary $ function in which you collect all function to be executed at domready event and then it's replaced later when you load jQuery at the bottom of the page.
You could load jQuery at bottom of the page, not in <head>. It will still use bandwidth, but it should be visually faster.

Categories