http://jsfiddle.net/NCt4D/
I want it to move (the image is large), but it dont work.
Firebug says reference scrollDivDown is not defined, but it's there?
It's JS fiddle.
Under "Choose framework", select "no wrap (body)". This prints your code at the end of your content and not wrapped in a function. This is what you would normally/ideally do to a script, which is load them after content, but before the body closes.
and like what the #jcomeau_ictx said, event handlers don't need the (). they just require the name (technically, the reference of) the function you want to execute. additionally, if you want to execute more functions on load, than just scrollDivDown, you can do:
window.onload = function(){
scrollDivDown();
foo();
bar();
baz();
}
also, prepend the subject of your handler (in this case, window) before the onload. although the subject is implied as window in the global scope, just prepend it to avoid confusion. It's also best practice to do so as well.
http://jsfiddle.net/NCt4D/1/
scrollDivDown was inside a closure and therefore was not accessible in the global scope where the timeout was executing in.
window.onload = scrollDivDown; // do not append ()
Related
I have a website that has a lot of popups, whenever a user load a popup (via ajax) there is a JavaScript code also loaded in the popup, I want this JavaScript code to be removed when its popup removed.
Main site code:
<body>
...
<div id="popup" style="display:none">
</div>
...
</body>
and then a loader in js file:
$.ajax('url',{
success:function(data){
$("#popup").show().html(data);
};
});
one of the views that ajax call and push it in the popup:
some html codes
<script>
$(document).on('click',function(){
console.log("document click");
});
</script>
when the user closes the popup, I use this code to empty the popup:
$("#popup").hide().html("");
but this doesn't end the on click event that was loaded, and any functions in the view will still exist in the memory and can be called!
this is an issue because I have a lot of popups here, and JavaScript eats the memory after a while, so I need to refresh the browser after using the website for some time, plus, events are duplicated whenever the popup reloaded!
If it not possible to clear these JS from the memory, are there any workaround for it?
What I get from your question (if I understood it correctly) is you need a way to clean up your memory from unused functions (maybe variables too) with some events listeners, Here is my approach:
#1 - Use removeEventListener
removeEventListener is a method used to remove unwanted events listeners from event target for example:
// add click event to the body
document.body.addEventListener('click', function clickHandler(){
console.log("document click");
});
// remove click event from the body
document.body.removeEventListener("click", clickHandler)
#2 - Garbage Collection
JavaScript does not provide a direct way to clean up the memory from unnecessary data (function declaration or variables declaration) but we can trick it using Garbage Collection. Garbage Collection uses an algorithm for cleaning up the memory from unnecessary data called Mark and Sweep. Basically this algorithm clean up the memory through marking of all the nodes (Objects) that are not reachable though the root node (which is the global object in JavaScript) and remove them from the memory. We can use this to our advantage by using two things (IIEF and Block-Scoping).
IIFE
IIFE is an acronym for Immediately Invoked Function Expression. If you go more deep about IIFE you will find that the function created inside (...) are hiding in a different scope other than the global scope, which means that by creating a function as an IIFE we will prevent the global Object from accessing it which means it will get removed from memory by the Garbage Collector after it gets executed.
Take a look at this example:
(function foo() {
// your code goes here
})()
console.log(foo) // ReferenceError: foo is not defined
Block-Scoping
Introduction to Scope
A block statement is used to group zero or more statements. The block is delimited by a pair of braces {...} and may optionally be labelled.
If you declared your variables inside it using the let or const keywords, Your variables will be not reachable by the global object and then can be removed from memory by the Garbage Collector after it gets executed.
Take a look at this example:
function foo(data) {
// do something with the data
}
{
let someBigData = []
foo(someBigData)
}
console.log(someBigData) // ReferenceError: someBigData is not defined
I have observed a strange behavior while learning jQuery and Javascript. When I call a variable that is defined inside the $(document).ready, from outside these tags it appears undefined, even when I define it as a global variable,
For example:
$(document).ready(function() {
myVar = "test";
});
alert(typeof(myVar));
//Results "undefined"
If I call the same variable inside the document.ready tags it works as expected
$(document).ready(function() {
myVar = "test";
alert(typeof(myVar));
//Results "String"
});
The result is same even after using window prefix.
$(document).ready(function() {
window.myVar = "test";
});
alert(typeof(window.myVar));
//Results "undefined"
I understand about the variable scopes but why even global variables aren't working this way. I am so confused.
The code inside the "ready" handler will not run until the DOM has been fully built. The code outside the handler will run as soon as it is encountered. Thus, your alert() runs before the code in the handler runs, so the outcome makes perfect sense: the global variable has not yet been initialized, so its value is undefined.
You can see the sequence of execution clearly by putting alert() (or, better, console.log()) calls inside the "ready" handler:
$(document).ready(function() {
console.log("In the 'ready' handler");
});
console.log("Outside the 'ready' handler");
When that runs, you'll see the "Outside" message logged first.
Because the alert() is executed before your document is perfectly ready.. You may try even by declaring the variable before $(document).ready() still it will return undefined..
The $(document).ready() gets fired after the page is fully loaded
When the script tag is fully loaded the alert gets executed.
So
Script tag is loaded => Execute alert
Continue loading page
Page completly loaded => fire $(document).ready
You var is getting set
The alert gets executed before your var is set
The other answers are correct but it is probably important to also note the $(document).ready(...) is also hiding your variable from the global scope. You could declare your variable then update it within the function
var myVar;
$(document).ready(function() {
myVar = "test";
});
console.log(myVar) // test
The execution plan it's like
//this statement shall fix the driver, not run it
$(document).ready(function() {//-->this it's an event handler waiting to be fired when content is fully loaded
myVar = "test";//-->myVar won't exists until this event is triggered
});
//this execute the alert function but myVar not exist yet
alert(typeof(myVar));
$(document).ready() is like to assign an event who will execute after the content is loaded, which means alert(myVar) will run before the lambda execution which was set as the content-loaded event. I hope you'll understand me.
// test.js //
var testObj = {};
testObj.init = function(){
console.log('google');
}
var onload = testObj.init;
/// what does it mean, does it mean it gets executed when script loaded or what, I just can't understand it as it is not looging into console anything under Google Chrome plugin...
Think of it like giving your dog 2 names:
var spot = new Dog();
var comeHereSpot = function () { return spot; }
var comeHereBoy = comeHereSpot;
Whether you call comeHereSpot or comeHereBoy the same dog will come running.
It just means that your variable onload now points to
function(){
console.log('google');
}
onload is just the name of a local variable here.
It means that variable onload is a reference to the function testObj.init. onload() will execute the function and output 'google' to the console.
No, it only means that you assign it to a variable named onload.
Depending on the scope of the code it might actually work, if the variable name collides with the onload property of the window object. In that case a variable would not be created, but it would use the existing property instead. You should not rely on this behaviour though, you should always specify it as a property of the object:
window.onload = testObj.init;
In your code, onload is simply the name of a local variable. The var keyword declares local variables. You're setting the value of onload to testObj.init, which is a function that prints 'google' to the console.
To make it run the function on page load, set window.onload to the value of the function.
window.onload = testObj.init;
Or, better yet, use event handlers to attach an "onload" event to the window object. (To make this easier, use a JavaScript library such as jQuery, but I recommend you first learn how it all works.)
Nothing is logged because you are simply setting onload to be a pointer to the function testObj.init which only gets the function's code. To actually run it, you must call testObj.init().
More about onload…
onload is a property of an HTML element that can be set to run javascript. For example:
<html>…
… <body onload="testObj.init()"> …
…</html>
This means that when the "body" element is loaded, the function testObj.init() is run.
The "onload" property can also be attatched by javascript, as in:
window.onload=myFunction();
I have a 2000 line jquery file, I just broke up the file into smaller ones, If I have a function in the first file, that file # 2 is referring to, it's coming up undefined.
Every file is is wrapped in a jquery ready function, What's the best way to do this?
If the function in question is declared within the scope of the ready handler, it won't be accessible to any other code, including other ready handlers.
What you need to do is define the function in the global scope:
function foo()
{
alert('foo');
}
$(document).ready(function()
{
foo();
});
P.S. A more concise way of adding a ready handler is this:
$(function()
{
foo();
});
Edit: If the contents of each of your divided ready handlers rely on the previous sections, then you can't split them up, for the reasons outlines above. What would be more sensible would be to factor out the bulk of the logic into independent functions, put these in their own files outside the ready event handler, and then call them from within the handler.
Edit: To further clarify, consider this handler:
$(function()
{
var foo = 'foo';
var bar = 'bar';
alert(foo);
alert(bar);
});
I might then split this up:
$(function()
{
var foo = 'foo';
var bar = 'bar';
});
$(function()
{
alert(foo);
alert(bar);
});
The problem with this is that foo and bar are defined in the first handler, and when they are used in the second handler, they have gone out of scope.
Any continuous flow of logic like this needs to be in the same scope (in this case, the event handler).
Function definition should not be wrapped in another function. Not unless you really want that function definition to be private. And if I understand correctly that's not your intention.
Only wrap function invocation in the jQuery ready function.
If you're worried about your functions clashing with third party function names then namespace them:
var myFunctions = {}
myFunctions.doThis = function () {}
myFunctions.doThat = function () {}
But really, you only need to worry about this if you're creating a mashup or library for others to use. On your own site YOU have control of what gets included in javascript.
Actually, for performance reasons, it may be better to keep it in one file; multiple requests actually can take up more bandwidth... but as separate files, you would need to order them in a particular order so that there is a logical sequence. Instead of having everything in a document.ready, have each script define a method, that the page will execute within its own document.ready handler, so that you can maintain that order.
Most likely the reason it's coming up undefined is because when you have separate ready calls, the scope of the code inside those calls is different.
I would reorganize my code. Any shared functions can be attached to the jQuery object directly, using $.extend. This is what we do for our application and it works well.
See this question. Hope it helps.
Everyfile shouldnt have a ready function. Only one file should have the ready function and that should be the last file.
"wrapped in a jquery ready function" is nothing else than binding stuff to the ready event that is fired when jQuery thinks the DOM is ready.
You should only bind methods that is depending on the DOM to the ready event. It doesnt matter how many binds you make, all of the methods will be executed in the binding order in the end.
Functions provide scope in JavaScript. Your code in the jquery.ready is an anonymous function, so it is unaware of the other scopes. remove the wrappings for those JavaScript functions and declare them as regular functions, a la
$(document).ready(function ()
{
functionFromFile1();
functionFromFile2();
};
I am writing a web application that has a static outer "shell" and a dynamic content section. The dynamic content section has many updates as users navigate the system. When a new content block is loaded, it may also optionally load another JavaScript file. In the name of good housekeeping, I remove script blocks from the DOM that apply to old content blocks, since that JavaScript is no longer needed.
The problem comes next, when I realized that although I have removed the <script> element from the DOM, the JavaScript that was previously evaluated is still available for execution. That makes sense of course, but I'm worried that it may cause a memory leak if the users navigate to a lot of different sections.
The question then, is should I be worried about this situation? If so, is there a way to force the browser to cleanup stale JavaScript?
<theory>You could go with a more object-oriented approach, and build the model in a way that each block of javascript blocks come in as their own objects, with their own methods. Upon unloading it, you simply set that object to null.</theory>
(This is fairly off-the-cuff.)
Memory use is indeed an issue you need to be concerned with in the current browser state of the art, although unless we're talking about quite a lot of code, I don't know that code size is the issue (it's usually DOM size, and leftover event handlers).
You could use a pattern for your loadable modules that would make it much easier to unload them en mass -- or at least, to let the browser know it can unload them.
Consider:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function MyModule() {
function foo() {
bar();
}
function bar() {
}
}
return MyModule;
})();
That defines a closure that contains the functions foo and bar, which can call each other in the normal way. Note that code outside functions runs immediately.
Provided you don't pass out any references to what's inside the closure to anything outside it, then window.MyModule will be the only reference to that closure and its execution context. To unload it:
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
That tells the JavaScript environment you're not using that property anymore, and makes anything it references available for garbage collection. When and whether that collection happens is obviously implementation-dependent.
Note that it will be important if you hook event handlers within the module to unhook them before unloading. You could do that by returning a reference to a destructor function instead of the main closure:
window.MyModule = (function() {
alert('This happens the moment the module is loaded.');
function foo() {
bar();
}
function bar() {
}
function destructor() {
// Unhook event handlers here
}
return destructor;
})();
Unhooking is then:
if (window.MyModule) {
try {
window.MyModule();
}
catch (e) {
}
try {
delete window.MyModule;
}
catch (e) {
// Work around IE bug that doesn't allow `delete` on `window` properties
window.MyModule = undefined;
}
}
If you save the evaluated code in namespaces, such as:
var MYAPP = {
myFunc: function(a) { ... }
}
"Freeing" the whole thing should be as simple as setting MYPP to some random value, ala
MYAPP = 1
This does depend on there being no other means of referencing the variable, which isn't trivial
How about loading the JS files into an iframe? Then (in theory, never tested it myself) you can remove the iframe from the DOM and remove the "memory" it's using.
I think... or I hope...
If you are worried about memory leaks then you will want to make certain that there is no event handlers in the code you want removed referring to the still existing dom tree.
It may be that you need to keep a list of all event handlers your code added, and before unloading, go through and remove the event handlers.
I have never done it that way, I always worry about when I remove nodes that there is still a reference.
Here is a good article on javascript memory leaks:
http://javascript.crockford.com/memory/leak.html
JavaScript interpreters have garbage collectors. In other words, if you don't reference anything, it won't be keeping them around.
One of the reasons why it is good to use JSON with a callback function (JSONP).
example, if you HTTP response for each JS is:
callback({status: '1', resp: [resp here..]});
And if callback() does not create a reference to the JSON object passed in as an argument, it will be garbage collected after the function completes.
If you really need to make a reference, then you probably need that data around for some reason - otherwise you would/should NOT have referenced it in the first place.
The methods mentioned to namespace objects just creates a reference that will be persisted until the reference count comes to 0. In other words, you have to track every reference and delete it later, which can be hard when you have closures and references from DOM lying around. Just one reference will keep the object in memory, and some simple operations may create references without you realizing it.
Nice discussion. Clears up a lot of things. I have another worry, though.
If I bind window.MyModule.bar() to an event, what happens if the event accidentally gets triggered after window.MyModule is deleted? For me, the whole point of namespacing and separating js into dynamically loaded modules is to avoid triggering event handlers cross-module by mistake.
For example, if I do (excuse my jQuery):
$('.some-class').click(window.MyModule.bar);
What happens if I delete window.MyModule, load another module, and click on an element which accidentally has a class called some-class?