A function that gets called outside the flow of control? - javascript

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.

Related

Jquery - cycling within a class [duplicate]

This question already has an answer here:
JavaScript setTimeOut doesn't seem to work like I expect
(1 answer)
Closed 4 years ago.
Relative newcomer to JS trying to keep my code class-oriented for the sake of best practice. I found a piece of code here for a text cycling effect I wanted to employ on a project. Using the code as-is within my main App.js worked fine. I then attempted to make it class/module oriented for later possible recycling, but thus far I've hit a brick wall. Passing console logs instead I've noticed that my attempts to use SetInterval, both within the class and in my App.js file calling the class into my HTML, don't seem to work, never properly looping more than once outside of isolating it.
Here's the current state of my code, possibly far removed from what I was doing previously, but it should give an idea where my head's at.
TextCycle.js:
import $ from 'jquery';
class TextCycle{
constructor(){
this.cycledText = $('.cycled-text');
this.i = 0;
}
cycle(){
//this.cycledText.removeClass('cycled-text--active');
//this.cycledText.eq(this.i).addClass('cycled-text--active');
this.i++;
console.log(this.i);
}
}
export default TextCycle;
App.js:
import TextCycle from './components/TextCycle';
var textCycle = new TextCycle();
setInterval(textCycle.cycle(), 3000);
Given I have a working version this isn't a critical issue, but given the point was practicing this sort of JS organization and modularization due to how I was taught, any insight on making this work is immensely helpful!
There is a problem with the way you're using setInterval() , along with your call to .cycle().
In short, you will want to update your code that calls setInterval so that cycle() is only called during the callback. Something like this would do:
setInterval(function() { textCycle.cycle() }, 3000);
One of the reasons your current code fails is that, textCycle.cycle() is called immediately, during this line:
setInterval(textCycle.cycle(), 3000); // Notice the () after cycle?
// That's causing the cycle
// method to be called immediately
By placing this in a callback function, as shown above, this does a few things:
it ensures that cycle() is invoked from the correct context (ie the context of your textCycle object. That basically means that when your use this inside of cycle(), then this will be the textCycle object, rather than the global object
it ensures that the cycle() method only gets invoked during the setInterval "callback", which is called on your set internal, rather than being called immediately
Hope this helps!

calling a function using a mouse event without attaching it to an HTML element?

I am taking a web development class. Today the teacher gave us a piece of code that raised some questions that I haven't been able to satisfactorily solve through my own searching. The code in question was essentially this:
<script>
function selectmouse(e){
...
...
}
document.onmousedown = selectmouse;
</script>
My first question, is this a legitimate way of calling functions? Is this something that is done? I am of course familiar with the typical way of calling functions from HTML elements, for example
<body onmousedown="selectmouse(event)">
The code was supposed to be calling the function and passing it the event object for the onmousedown. After playing with the code for a while I found a few unusual things.
First, if I put parenthesis after the function call, like I am used to doing (i.e. selectmouse();), then the function resolved immediately upon loading the page, with a value of 'undefined' for the variable. This makes intuitive sense to me, because I assume the browser is treating it like a variable assignment and therefore calling the function as it parses the code, as it normally would to assign a variable.
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to. It would call the function when the mouse was pressed in any part of the body, and it sent the event object as the variable for the function. But I can't figure out why. I can't find reference to anything similar to it online, and I've never seen anything like it before. Is this a legitimate way to do something like this? Or is this bad code that happens to be working for some reason and would probably cause problems in the future? Why is it working?
document.onmousedown = selectmouse; //note: never do this except in old browsers
However the part that is weird to me happened when I deleted the '()' and left it as it is coded above. In this instance it seemed to function like she wanted it to.
That's not weird. You are passing the reference of the function to the browser, not executing it.
For example, you have this function:
function callback(){
alert("clicked!");
}
document.body.onclick = callback;
You pass the reference to onclick and the browser will know what function to call when the event is triggered. But if you do it like this:
document.body.onclick = callback();
This will be evaluated into:
document.body.onclick = alert("clicked!");
//Note that this is simplified explanation to visualize what is happening.
//The returned value of alert() is not assigned to onclick.
//To be exact the returned value of callback() is the one that is being assigned.
//Similar to:
// ...onclick = (function(){ alert("clicked!"); })();
Then you will see an alert, and the browser will continue executing the rest of the code:
document.body.onclick = undefined;
<body onmousedown="selectmouse(event)"> <!-- Don't do this too -->
The parentheses are necessary because this code is not executed instantly. It is only executed when the event is triggered.
Anyway, you shouldn't attach events both using .onmousedown or onmousdown="...". There is a better way of doing it:
element.addEventListener("mousedown", callback, false);
Reason: If you use the onmousedown property, you can only attach one mousedown event. In most cases you would want to attach more than one.
Also attaching events inline might cause security problems (cross-site scripting), and that is exactly why Google decided to prohibit all developers from using them in developing Chrome apps/extensions.
This is legitimate code and is working as it should.
The way you are comfortable with is just a method we tried while the web was evolving, but at present we should better use the second way you showed, although its changed bit more to make you understand it in a better way using event bindings.
When you do
function selectmouse(e){
...
...
}
javascript will create a variable named selectmouse and save the function in that variable. So selectmouse is a variable of type function with the function body as its value.
document on the other hand can be related to class or specifically an object which is an instance. Each document and each HTML element or DOM node can have in it variables to store the functions to be called on user events like onmousedown.
so when doing
document.onmousedown = selectmouse;
we are inturn saying
when mousedown happens in document, the function named selectmouse
should be called
If you do
document.onmousedown = selectmouse();
it means
run the function selectmouse immediately and get the result, assign
the result to onmousedown event of the DOM Node document.
And if you ask why this is taken apart from the form
<body onmousedown="selectmouse(event)">
To answer in a simple way, HTML is Hyper Text Markup Language, its sole purpose is to represent formatted data, the quick evolution of web inturn made it deranged with behaviours like this and presentation code like inline css. So to make behaviour and presentation out of HTML and thus a better design we do this.
Please take time to take a look at how you can bind a function to an event which is the current tradeoff in doing this same thing.
For a detailed explanation please check the events sectio of ppk blog here
I think that is correct, because the function is being called within the script as if it were an object, to me is not the best way to do it, I would have like this (with jquery):
$(document).mousedown(function (event) {
// here the content of the function
});
<body onmousedown="selectmouse(event)">
In this example the browser evaluates the result of the expression selectmouse(event) and assigns it to the onmousedown property of the body, event is undefined and the selectmouse doesn't return anything so it's result is undefined.
It is equivalent of the following if it was inside a script tag
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse(event);
</script>
<body onmousedown="selectmouse">
When you remove the () you are assigning a function to the onmousedown property. Now the browser fires your callback method whenever the mousedown event is raised and it bubbles up to the body, passing the current event as the parameter you're declaring as "e". If another element also had an onmousedown event handler declared but it cancelled the event ( by calling event.cancelBubble = true ) the body's onmousedown handler will not be invoked.
<script>
function selectmouse(e) {
}
document.body.onmousedown = selectmouse;
</script>

JavaScript Module Pattern(function(){})(); vs block statement

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.

Why windows.onload is executed several times?

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

Having a callback when a function is called without touching the actual function (jquery)?

I'm developing a small plugin that changes the favicons if there are unread messages in mailbox in Roundcubemail. However, the API sucks, and the event listupdate is fired only when the whole page is loaded, even if it is meant to fire when the list is updated.
However, I've managed to find out, that every time the list is updated, certain functions are called, such as set_unread_count. It gets the unread-count easily, so it would be great to somehow "append" stuff to this function. I just think based on hours of searching that there is no solution for this. Can I add a callback to be called when the set_unread_count is called? Can I somehow append stuff to that function? Any other ideas?
Create a little hook.
var _old_set_unread_count = set_unread_count;
set_unread_count = function() {
// do whatever you want here
// access arguments[x] to get arguments.
_old_set_unread_count.apply(this, arguments);
};
Demo: http://www.jsfiddle.net/4yUqL/69/

Categories

Resources