Execution of dynamically loaded JS files - javascript

I understand that JS is single threaded and synchronously executed. Therefore when i add a file to my browser head tag that file is executed as soon as its encountered. Then it goes to the next script tag & executes that file. My question is when I add a js file dynamically to an HTML head tag. How does the browser executes that file?
Is it like that the file is executed as soon as the file is loaded wherever the current execution is. Or is it that we can control how that file is executed?

When the script is loaded, it will be executed as soon as possible. That is, if some other javascript function is executing, like a clickhandler or whatever, that will be allowed to finish first - but this is a given because, as you say, in browsers JavaScript normally execute in a single thread.
You can't control that part of the script loading, but you could use this pattern - heavily inspired by JSONP:
inserted script:
(function () {
var module = {
init: function () {
/* ... */
}
}
ready(module); // hook into "parent script"
}());
script on main page:
function ready(o) {
// call init in loaded whenever you are ready for it...
setTimeout(function () { o.init(); }, 1000);
}
The key here is the ready function that is defined on your page, and called from the script you insert dynmaically. Instead of immediately starting to act, the script will only tell the parent page that it is loaded, and the parent page can then call back to the inserted scripts init function whenever it wants execution to start.

What happens when a JavaScript file is dynamically loaded ( very simplified, no checks ):
the file is loaded;
if there is function call e.g. doSomething() or (function(){...})(), the code is executed(of course you must have the definitions);
if there are only function definitions, nothing is happening until the function call.
See this example: 3 files are loaded, 2 are executed immediately, 1 is waiting the timeout.
Edit:
The script tag can be placed anywhere in the page. Actually it is better to be placed at the end of the page if the onload event is not used (yahoo speed tips).
With HTML5 JavaScript has web workers MDN MSDN wikipedia.

Considering a way to do this is
var js=document.createElement('script')
js.setAttribute("type","text/javascript")
js.setAttribute("src", filename)
document.getElementsByTagName("head")[0].appendChild(js);
// ^ However this technique has been pointed to be not so trusworthy (Read the link in the comment by Pomeh)
But answering your question
How does the browser executes that file?
As soon as the script is added to the DOM
Is it like that the file is executed as soon as the file is loaded wherever the current execution is?
Yes
Or is it that we can control how that file is executed?
Its better if you attach an onload event handler, rather than a nasty tricks.

Here is some code you can try to get an answer to your question.
<script>
var s = document.createElement('script'), f = 1;
s.src="http://code.jquery.com/jquery-1.7.2.js";
document.head.appendChild(s)
s.onload = function(){
console.log(2);
f = 0
}
while(f){
console.log(1);
}
</script>
This code should ideally print a 2 when the script loads, but if you notice, that never happens
​
Note: This WILL kill you browser!

Related

Executing Javascripts in a specific order

I have three (3) javascripts that I am trying to execute in a specific order. My problem is that each javascript uses data set by the previous script. My first script, which executes on loading, gets data from an SQL database and copies it to the body of my web page. The next javascript needs some of this data to execute properly In order to execute the second script, I must wait not only until the previous script has completed execution but until the data has been loaded to the body of my web page so that it can be accessed by the second script. The relationship between the second and third scripts is similar. I've not been able to find any previous question and answer that addresses the use of data extracted by a previous script. Any help that you can offer will be very much appreciated. Here's an example of my latest attempt.
function myFunction()
{
document.getElementById("inputCounter").innerHTML = 1;
var recordCounter = document.getElementById("inputCounter");
var number = recordCounter.innerHTML;
querySQL(number);
document.onreadystatechange = function()
{
if (document.readystate == "complete")
{
getIPDetail('https://freegeoip.net/csv/');
}
};
}
myFunction() executes on loading of the page body. The first script called from myFuntion() is querySQL(number). The second script called from myFunction() is getIPDetail('https://freegeoip/csv/'). My problem is that detIPDetail... does not execute because it needs data that querySQL inserts into a div on the page body.
I was able to solve this problem through experimentation. In other words, I found the right positions in my code to put the javascript function calls so that my application flowed properly.

Writing Javascript library: Asynch load timing issue

In the JS library I am writing, I have this loadScript func:
function loadScript(src, callback) {
var script = document.createElement('script');
script.src = src;
// script.type = "text/javascript";
// script.async = false;
if (typeof callback !== 'undefined') {
script.onload = function () {
callback();
};
}
document.head.appendChild(script);
}
Inside the main js file, I use it to load the dependencies dynamically after the main js file is loaded, initiate the JSLib object in its callback.
loadScript(baseUrl + '/dependencies/you-load-me-long-time.js', function() {
window.JSLib = true;
}
Then I have a web page that calls this library.
var jsLib = new JSLib({...});
The problem that I encounter is that - in the web page that loads this JS library, the browser complains that the JSLib is not defined because the dependency file you-load-me-long-time.js has not finished loading yet when the script in the web page is executed.
A work-around that seems to be working for now is that, in the web page, I wrap the initiation code in a $(window).load(function() {}); call.
Is there any way that I can overcome this timing issue? ex: "blocking" the loading of the rest of the web page until JSLib is loaded (doesn't sound like a good idea anyway), etc...
There are only two ways to create blocking dynamic script loaded via JS and both are fairly undesirable.
If the document is still being parsed, you can use document.write() to insert a <script> tag at the current document location. That will then be parsed and loaded synchronously.
If the script resource is on the same origin as the document, you can fetch the script with a synchronous Ajax call and then eval the script.
Since neither of these is particularly desirable, the usual work-around is to surface a callback all the way back to the caller of the script so that they can participate in when the async operation is done and put their code in that async callback.
var jsLib = new JSLib({...}, function() {
// put code here that uses the jsLib because now it is loaded
});
For this messy reason, it is usually not a good practice to make the completion of a constructor be an async operation. It significantly complicates the use of the object.
More common would be to let the constructor just create the shell of the object and then require a .load(fn) method call to actually load it. This will likely lessen the chance of callers misuing the library.
var jsLib = new JSLib({....});
jsLib.load(function(err) {
if (err) {
// error loading the library
} else {
// library is loaded now and all functionality can be used
}
});
FYI, your idea to use $(window).load() is not a good idea. That method may accidentally work just because it delays the timing enough until your script happens to be loaded, but the window load event does not specifically wait until dynamically loaded scripts have been loaded so it is not a reliable way to wait for your script.

Unload JS loaded via load() to avoid duplicates?

I'm building a dynamic website that loads all pages inside a "body" div via jquery's load(). The problem is I have a script looped with setInterval inside the loaded PHP page, the reason being I want the script loaded only when that page is displayed. Now I discovered that the scripts keep running even after "leaving" the page (loading something else inside the div without refresh) and if I keep leaving / returning the loops stack up flooding my server with GET requests (from the javascript).
What's a good way to unload all JS once you leave the page? I could do a simple dummy var to not load scripts twice, but I would like to stop the loop after leaving the page because it's causing useless traffic and spouting console errors as elements it's supposed to fill are no longer there.
Sorry if this has already been asked, but it's pretty hard to come up with keywords for this.
1) why don't you try with clearInterval?
2) if you have a general (main) function a( ) { ... } doing something you can just override it with function a() { }; doing nothing
3) if you null the references to something it will be garbage collected
no code provided, so no more I can do to help you
This really sounds like you need to reevaluate your design. Either you need to drop ajax, or you need to not have collisions in you method names.
You can review this link: http://www.javascriptkit.com/javatutors/loadjavascriptcss2.shtml
Which gives information on how to remove the javascript from the DOM. However, modern browsers will leave the code in memory on the browser.
Since you are not dealing with real page loads/unloads I would build a system that simulates an unload event.
var myUnload = (function () {
var queue = [],
myUnload = function () {
queue.forEach(function (unloadFunc) {
undloadFunc();
});
queue = [];
};
myUnload.add = function (unloadFunc) {
queue.push(unloadFunc);
};
return myUnload;
}());
The code that loads the new pages should just run myUnload() before it loads the new page in.
function loadPage(url) {
myUnload();
$('#page').load(url);
}
Any code that is loaded by a page can call myUnload.add() to register a cleanup function that should be run when a new page is loaded.
// some .js file that is loaded by a page
(function () {
var doSomething = function () {
// do something here
},
timer = setInterval(doSomething, 1000);
// register our cleanup callback with unload event system
myUnload.add(function () {
// since all of this code is isolated in an IIFE,
// clearing the timer will remove the last reference to
// doSomething and it will automatically be GCed
// This callback, the timer var and the enclosing IIFE
// will be GCed too when myUnload sets queue back to an empty array.
clearInterval(timer);
});
}());

How can one simulate events triggered on load when adding javascript to a page through the browser's console?

I'm currently working on a script to be placed on a 3rd-party site...in order to test it I'm opening the 3rd party's site and running the script in the browser's console (Chrome). Some code I need to executed on window.load(), but that code isn't being executed with this method of testing. I'm assuming it's because the code bound by load to the window is being bound after the load event has taken place, thus never being triggered. My question has two parts:
Is the reason that window.load is not being triggered in fact because it's being added after the load event has been triggered? Or is this wrong and there is likely a problem elsewhere?
How best can one simulate events triggered on load when appending javascript through the console like this?
if(document.readyState === "complete"){ will detect if the load is already complete.
You could easily use an else and then put in the load event handler if it hasn't finished loading yet. Something along the lines of:
if(document.readyState === "complete"){
// do stuff
}else{
// attach load handler
}
What I like to do is define a pageLoaded type function that I can run at a later point with my code, that way I can call it immediately if the page is already loaded, or let the load handler call it when the page load does fire. Something like:
var pageLoaded = function(){alert("Page is ready!");}
if(document.readyState === "complete"){
pageLoaded()
}else{
// attach load handler, calls pageLoaded()
}
Of course, since you tagged your question as jQuery you could always just wrap all your code in jQuery's handy dandy ready function shorthand:
$(function(){
// do stuff
});
This passes your anonymous function to jQuery where it will do something very similar if not identical to the above vanilla javascript.
Define your event in a function and then call that function from the console.
function do_this_on_load() { alert("Loaded!") }
$(window).load(do_this_on_load);
Then you can from the console run:
do_this_on_load();
to see what it does on the page.

What is an efficient way of waiting for a dynamically loaded Javascript file to finish loading?

I'm loading a Javascript file that has a function in it that I'd like to call. This is not possible, since between 'initiating' the load, and actually calling the function, the JS isn't loaded yet. Of course, I could do something like setTimeout('functionCall();',5000);, but I don't think this is a very efficient method, and it seems really unstable to me. That's why I was wondering whether there was a better way to do it.
Here's the code I'm using. The function in question is called controllerStart. If I comment out the last line here, and type it into a Javascript terminal (like on Chrome developer tools), everything works.
function loadController(name){
clearAll();
scriptContainer.innerHTML = '';
var scriptElement = document.createElement('script');
scriptElement.setAttribute('src','controllers/' + name + '.js');
scriptElement.setAttribute('type','text/javascript');
scriptContainer.appendChild(scriptElement);
controllerStart();// <-- Doesn't work from here, but works on a terminal
}
Thanks for taking a look!
call the function after you reference the Javascript.
JS loading is SYNCHRONOUS.
So.....
---- js library call -----
----- call the function here -----
Profit!
edit: specifically :
function loadController(name){
clearAll();
scriptContainer.innerHTML = '';
var scriptElement = document.createElement('script');
scriptElement.setAttribute('src','controllers/' + name + '.js');
scriptElement.setAttribute('type','text/javascript');
scriptContainer.appendChild(scriptElement);
scriptElement.onload = new function(){controllerStart();};
//something like that.
}
edit 2: my bad - use "onload" not "load" - too much jquery on the brain
more about "onload" here: http://www.onlinetools.org/articles/unobtrusivejavascript/chapter4.html
There is a good post from Nicholas C. Zackas about it which you can read here, that includes just the code you want to use.
Basically it's just a function that includes both a URL of a JS file to load, and a callback to execute when it's been loaded. It then creates the <script> tag, attaches the callback to execute after it's loaded (via the onreadystatechange or the onload event) and inserts it into the DOM.
Then, all you need to do is call it like:
loadScript('controllers/' + name + '.js', controllerStart);
From the sound of it you're loading your JavaScript asynchronously. In more recent browsers there's an onload event on the tag which fires when it's finished loading. But if you need cross-browser support, the only way to do it is to either:
(a) if it's loaded from the same server as your page, load your javascript using AJAX and then execute it with eval() when it's loaded (instead of using <script> tags),
(b) if you control the file add an event trigger to the end of it which you then listen for in your main JavaScript file. JQuery's bind() and trigger() functions are handy for that.
(c) if it's loaded from somewhere else and you don't control it (but do have permission to redistribute it), relocate it to your server and follow (a).
You also could do away with asynchronous loading and just put a stream of <script> tags in your header, the old fashioned way. That guarantees that each script won't be run until after the previous script has finished.

Categories