I saw an answer to some question earlier that used my "Weird" example, and I was wondering if there was any benefit to either method.
Some HTML:
<span id="them">Hey</span>
<span id="me">Hey</span>
What is the difference between:
(function()//doing this
{
them.innerHTML = "Weird<br>";
})();
me.innerHTML = "Not so weird<br>";//and doing this
And even, why do people use window.onload when they can put scripts at the bottom of the body? Or is it just a matter of personal preference?
Your first code snippet: is a Module Pattern Or Immediately Invoked Function Expression(IIFE)
(function()//doing this
{
them.innerHTML = "Weird<br>";
})();
This when encountered by the Javascript compiler will immediately invoke the function when it encounters (); and keeps the variables and functions within its scope.
You must read Java-script Design Patterns to better understand its use and benefits.
Second code snippet: is just a JavaScript statement.
me.innerHTML = "Not so weird<br>";//and doing this
This when encountered by the JavaScript compiler will immediately execute it.
Remember both snippets executions depends on where its placed.
So, to answer your other question. window.onload is an event fired when the HTML DOM is fully loaded and browser can read all its elements.
There is no difference between your two examples. Your first example creates an anonymous function that immediately executes (called an Immediately Invoked Function Expression). Your second example just executes the same code.
You have to wait until a browser reads all the HTML elements before you can change them with JavaScript. The onload event fires when the page has fully loaded and at that time the browser knows about all the HTML elements. However, a browser won't fire the onload event until after the page has fully loaded, which means the browser will wait until after a large image has fully loaded -- even though the browser has already parsed the rest of the HTML -- making your JavaScript needlessly wait until the image finishes loading. Because the browser knows about all the HTML before the image finishes loading there is no reason to prevent JavaScript from executing earlier.
Once people discovered that onload was waiting too long before allowing the JavaScript to execute, people started putting their JavaScript right before the closing <body> tag (without using onload), so that the JavaScript would execute as soon as all the HTML had been parsed (except for the closing <body> tag), and that way their JavaScript could start executing sooner than when using window.onload.
Now JavaScript libraries like jQuery have an event that fires when the browser knows about all the HTML -- even though the page hasn't fully loaded (e.g. due to images that haven't fully loaded).
In your simple example, there is no difference between the result of the two cases. Both accomplish the same thing.
The reason for using this structure:
(function()//doing this
{
them.innerHTML = "Weird<br>";
})();
Is to create a function scope that can be used to hold private or temporary variables or to create a closure without exposing the variables inside to the outside world.
As for your second question, window.onload fires at a different time than scripts placed at the end of the body because window.onload fires when all synchronous resources needed by the page have finished loading (like scripts and images). It can be used, either to get notified when all these resources are done loading or it can be used by code that cannot be easily located at the end of the body as a safe time when the page is ready though it is usually not necessary to wait that long just for the DOM to be safe.
In the above case there is not advantage in using the first method.
But the first method is preferable in scenarios where you need to create some variables/method but does not want to pollute the global name space
After some thought, there is a benefit over writing the extra (function(){})(); as shown (imagine the code is huge):
(function()
{
var text = "Span 'them' text!";
them.innerHTML = text;
//Many lines of code
})();
(function()
{
me.innerHTML = text;//will throw 'text is undefined'
//Many lines of code
})();
This will be quite handy for debugging many lines of code, the debugger would recognise the error and "point" straight to it.
Whereas with this example:
var text = "Span 'them' text!";
them.innerHTML = text;
//Many lines of code
//...
me.innerHTML = text;
Your "error" (which the debugger is perfectly happy with) would be much harder to track down.
Related
So, I've been trying to understand a specific js library by running it through my browser's debugger, and something happens that just confuses me.
I first encountered this in the Phaser game library, but I've seen it another library as well. I'll use Phaser as an example:
<script>
(function(){
var game = new Phaser.Game(800, 600, Phaser.CANVAS, '');
game.state.add('Game', Game);
game.state.start('Game');
})();
</script>
So that anonymous function finishes setting some things up, and I step over and out of that function, and after a couple more steps (the pointer just sitting at the top of the html doc in the meantime) my program out of nowhere ends up here:
Phaser.Device._readyCheck = function () {
var readyCheck = this._readyCheck;
....
}
It didn't look like anything within my flow of control called that function, so how did I get here? What's calling this function? I've read a bit about 'asynchronous functions' and that sounds like a pretty good explanation, but the stuff I've glanced at on Google don't really explain anything well, so I can't say I understand it enough to be sure. I'm relatively new to JavaScript.
The library sets up event handlers for various events which then get called asynchronously. In this case, event handlers are setup to to watch for the completion of the loading of the DOM, among other things, so that the internal state of the library can be initialized. You can see how it happens in the source
src/system/Device.js:Phaser.Device._readyCheck
and Phaser.Device.whenReady in the same file. With a little searching you can easily find who calls whenReady.
The function you pointed out at the top is a self-executing function. (); causes everything contained in the preceding parentheses to be executed immediately.
Both of the following code snippets worked:
Using IIFE in js file:
(function initialize() {
txtInput = document.getElementById('txtInput');
txtResult = document.getElementById('txtResult');
txtInput.value = "0";
txtResult.value = "0";
}());
Calling initialize() on window load event in html file:
window.addEventListener('load', initialize, false);
Is one a better approach than other; in terms of performance or otherwise? As it stands right now, I am leaning more towards adding event listener to the window object, because it is more readable.
It depends when you want the code to run. If you want the code to execute ASAP you can use an IIFE but there is really no point using an IIFE if you don't use it to protect your variables and/or not polluting the global scope.
(function initialize() {
// do somthing
}());
or
// do somthing
will execute at the same point in time.
If you want to defer execution there are three points in time usually used by web devs. <script>s at bottom, DOMContentLoad and window.onload.
<script>s at bottom will execute after they are fetched from the server.
DOMContentLoaded basicly execute as soon as </html> has been read by the HTML parser.
very simplified window.onload executes after all CSS, <img>es and <script>s have been loaded.
Note that in reality, with attributes like async and defer on <script>s, this is more complex, . This is why there is a mountain of resource loaders available.
Probably the result of each approach matters, not the performance. The first approach runs immediately while the second one waits until dom is ready. The end result is that in your first approach, you may end up getting undefined for both textInput and textResult, unless you place the script on the bottom of page.
The IIFE in a script element (whether inline or external loaded) just before the closing body element certainly appears most clever. It confuses the hell out of commoners.
document.addEventListener('DOMContentLoaded', function() ... is easy to understand. It's almost plain English: event listens for DOM content loaded. So, poof, the majesty is gone. Note this is distinct from window onload.
I use the event listener, as it adheres to the KISS principle, it's a purpose built tool, and it does what it says it does (which probably includes stuff/functionality I haven't even considered).
To see the problem in action, see this jsbin. Clicking on the button triggers the buttonHandler(), which looks like this:
function buttonHandler() {
var elm = document.getElementById("progress");
elm.innerHTML = "thinking";
longPrimeCalc();
}
You would expect that this code changes the text of the div to "thinking", and then runs longPrimeCalc(), an arithmetic function that takes a few seconds to complete. However, this is not what happens. Instead, "longPrimeCalc" completes first, and then the text is updated to "thinking" after it's done running, as if the order of the two lines of code were reversed.
It appears that the browser does not run "innerHTML" code synchronously, but instead creates a new thread for it that executes at its own leisure.
My questions:
What is happening under the hood that is leading to this behavior?
How can I get the browser to behave the way I would expect, that is, force it to update the "innerHTML" before it executes "longPrimeCalc()"?
I tested this in the latest version of chrome.
Your surmise is incorrect. The .innerHTML update does complete synchronously (and the browser most definitely does not create a new thread). The browser simply does not bother to update the window until your code is finished. If you were to interrogate the DOM in some way that required the view to be updated, then the browser would have no choice.
For example, right after you set the innerHTML, add this line:
var sz = elm.clientHeight; // whoops that's not it; hold on ...
edit — I might figure out a way to trick the browser, or it might be impossible; it's certainly true that launching your long computation in a separate event loop will make it work:
setTimeout(longPrimeCalc, 10); // not 0, at least not with Firefox!
A good lesson here is that browsers try hard not to do pointless re-flows of the page layout. If your code had gone off on a prime number vacation and then come back and updated the innerHTML again, the browser would have saved some pointless work. Even if it's not painting an updated layout, browsers still have to figure out what's happened to the DOM in order to provide consistent answers when things like element sizes and positions are interrogated.
I think the way it works is that the currently running code completes first, then all the page updates are done. In this case, calling longPrimeCalc causes more code to be executed, and only when it is done does the page update change.
To fix this you have to have the currently running code terminate, then start the calculation in another context. You can do that with setTimeout. I'm not sure if there's any other way besides that.
Here is a jsfiddle showing the behavior. You don't have to pass a callback to longPrimeCalc, you just have to create another function which does what you want with the return value. Essentially you want to defer the calculation to another "thread" of execution. Writing the code this way makes it obvious what you're doing (Updated again to make it potentially nicer):
function defer(f, callback) {
var proc = function() {
result = f();
if (callback) {
callback(result);
}
}
setTimeout(proc, 50);
}
function buttonHandler() {
var elm = document.getElementById("progress");
elm.innerHTML = "thinking...";
defer(longPrimeCalc, function (isPrime) {
if (isPrime) {
elm.innerHTML = "It was a prime!";
}
else {
elm.innerHTML = "It was not a prime =(";
}
});
}
I'm binding the window.onload event like this
// It's a little more complex than this, I analyze if there is any other function
// attached but for the sake of the question it's ok, this behaves the same.
window.onload = myfunction;
Onload is triggered twice on my local machine a several times on the production server
If I change it by the jQuery equivalent
$jQuery(window).load(myfunction);
It behaves as expected (executed only once).
Could you help me to understand possible reasons why the first option it's not working as supposed?
Thanks!
The parentheses on your assignment — myfunction() — executes your function. You haven't shown what myfunction does, but this means that the return value from that function is being assigned to window.onload, not the function itself. So, I don't know how that is getting executed, unless you have somehow got that to work, like ending the function with return this;
You want
window.onload = myfunction;
Given the nature of window.onload, it seems unlikely that pure browser events alone are making both calls to myfunction. Therefore, a breakpoint inside your function will help you see the call stack. I've included screenshots for Chrome.
Sample code:
var alertme = function() {
alert("Hello");
}
window.onload = alertme;
function testsecondcall() {
alertme();
}
testsecondcall();
Open your page in Chrome.
After the page has loaded once, open the Developer Tools panel and put a breakpoint on the line inside your function, then refresh the page.
Check the call stack of both times that it breaks. One will be empty (the actual window.onload). The other should give you some information like the following:
On the right, under "Call Stack", you see alertme is called by testsecondcall
i need answer of this question as soon as possible
i have 2 script tags in the same page, 2 with the same methods name
and i have a timer
on specific time i want to enable script1 with all method inside it to process
and in another time to enable all methods in script2
i am using every script to draw dif. thing in canvas.
example (psedo code):
<script1>
init(){
canvas.draw();
}
</script1>
<script2>
init(){
canvas.draw();
}
</script2>
<canvas>
i cant change method name ... how to call init from scrip1 or script2
or
how to snable script1 to call every thing from it then enable script2 to call every thing from it.
Both script tags will create script code in the same scope, so the second definition of init() will overwrite the first one. So without renaming them it's not going to work the way you want.
If you do rename one of them then you can just call it. Since they're in the same scope there's no actual "script1" and "script2" separation. Any methods/variables defined in one can be seen by the other.