I am looking for a way to keep on looping a couple of values. I am using a simple ajax load script, which get the value(s)(files) from a dataset from the target element. The re-loading of a file happens every XXXX second, so it will load the file over and over, but if there are more files present it should loop them all, and re-loop it....infinite
The example below is a basic idea how, I split the string and start with the first one, but how can i loop this(the best way), and keep it looping.
HTML
<div id="target" data-load="file1.php | file2.php | file3.php"></div>
jQuery
var fileTo = $('#target').data('widget-load').split("|");
setInterval(function(){
$('#target').load(fileTo[0])
},1000);
you can use a setTimeout("function",delay) to keep calling the same function within itself with a delay for milliseconds.
var fileTo = $('#target').data('widget-load').split("|");
setInterval(function(){
var file = fileTo.shift(); // `shift` gives the file at 0
$('#target').load(file); // load it
fileTo.push(file); // `push` adds it at the end of the array
},1000);
#Diode: in case of infinite loop, shift && push are the better choice. Forgot about them. In that case, I suggest the following:
var intervalId = setInterval((function(theArray)
{
var target = $('#target');
var current;
return function ()
{
current = theArray.shift();
target.load(current);
theArray.push(current);
};
})($('#target').data('widget-load').split("|")),1000);
Try this:
var intervalId = setInterval((function(theArray)
{
var target = $('#target');//only search for this once, not on every call
//to make infinite loop, copy the array
var resetArr = theArray.slice(0);//use slice, if not a reference is assigned and both arrays will be altered
//Name is not required, if you want to use a name, pick a better one, next might be reserved (not sure)
//best go for nextInterval, chose this one for explanation
return function next()
{
//get first element, theArray is now 1 shorter
target.load(theArray.splice(0,1)[0]);
if (theArray.length === 0)
{//no more files left -> this stops the interval
//clearInterval(intervalId);
//intervalId = null;
//restore the array, the loop starts from file1 again --> infinite loop
theArray = resetArr.slice(0);//copy the original value
}
}
})($('#target').data('widget-load').split("|")),1000);
This might be a little dense, but I tried a simple one-line version in chrome console:
foo = setInterval((function(arr){ return function(){alert(arr.splice(0,1)[0]); if (arr.length === 0){ clearInterval(foo);}};})([1,2,3]),1000);
And it works like a charm. How it works:
intervalId holds the, erm id of the interval... sort of a reference. As long as that is set, the function will be called every 1000ms. Instead of passing a simple function as first argument, I created a function, and call it instantly. The argument that I passed to the nameless function (theArray) can be accessed by the function called next, which is the return value of the anonymous function. It's created inside a function, so it has access to all variables of its mother function, even after the mother has returned. This means that the value of theArray is out of scope everywhere else except for the next function, which is the actual callback for our interval. Nothing can interfere with the value of theArray, nothing can be overwritten by any outside code, making this a vastly safer approach compared to use of globals. The same applies to the variable target: it was declared and initialized in the anonymous mother-function, which is called once and then GC'ed. The variable lives on though, and references a jQuery object. The DOM has only been searched once, for that element, but every new call to the next function has access to that object. Do this once and the speed difference is marginal, do this all the time and your scripts will be (a lot) more efficient!
So, interval: Every 1000ms, next is called. It shifts the first value from the array that was an argument (theArray) of its creator (that anonymous function). When that array is empty, the clearInterval function is called to stop the lot. All files are loaded, no point in carrying on. As soon as this happens, theArray, next-function, and all other variables (target) go out of scope, so no globals, just a nice, clean chunk of memory, which is always a good thing. I'm assuming this code will be triggered as part of an event handler, in which case you can just copy paste this into the handler, and again, no globals will be created.
If this code wíll be part of the global scope, you can easily avoid globals by just wrapping it all up in a self-invoking function:
(function()
{
var intervalId = setInterval((function(theArray)
{
//...
})($('#target').data('widget-load').split("|")),1000);
})();
And you're all set. IMHO this is the best, safest and most JS-minded approach to this problem. JavaScript is all about functions, the more you exploit them, the better the language likes it. In fact, it'll thank you for it by revealing its hidden expressive power.
Even if you decide not to use this answer, read up on stuff like closures and how to get the most out of function scopes. You'll soon catch yourself writing your code a whole new way, promise :)
var $target = $('#target'),
fileTo = $target.data('widget-load').split("|"),
i = 0;
setInterval(function(){
$target.load(fileTo[i]);
i++;
if (i === fileTo.length)
i = 0;
},1000);
Related
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I am an absolute newbie, and I just read this in JavaScript: The Good Parts.
In the chapter talking about scope, it says "It is important to understand that the inner function has access to the actual variables of the outer functions and not copies in order to avoid the following problem." And then the two following examples look like this:
//BAD EXAMPLE
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function (e) {
alert(i);
};
}
};
//END BAD EXAMPLE
var add_the_handlers = function (nodes) {
var helper = function (i) {
return function (e) {
alert(i);
};
};
var i;
for (i = 0; i < nodes.length; i += 1) {
modes[i].onclick = helper(i);
}
};
According to the author the second example is better because it doesn't use a loop inside the function, otherwise it could be wasteful computationally. But I am at loss and don't know what to do with them. How do I put his theory in real application? Can anyone illustrate these two examples combine HTML?
The problem is with closure. The inner functions have access to the variable i defined outside of these functions. After all iterations of the loop have been executed, the variable i will hold the value of nodes.length. So when you click on nodes[0], the alert will say nodes.length, which is not what you'd expect. (You would expect the alert to say 0.) The same holds when you click on nodes[1], nodes[2], etc. The alert for all of them will say nodes.length.
Firstly, in the bad example, a function is created for each event handler; the loop creates multiple function objects. Whereas in the second example, a single function is created and referenced from inside the loop. So you save a lot of memory.
Secondly, in the bad example, as the value of "i" runs, the function does not retain the value, and when it runs, it will always return the last value of "i". In the good example however, as "i" is passed into the function, this value is retained as the lexical environment of the function, and when it is called, it will return the correct value.
Thirdly, as mentioned by #Gary Hayes, we might want to use the function elsewhere too. So it's best to keep it independent of the loop.
You can check it with HTML working here: https://jsfiddle.net/vdrr4519/.
'multifunc' elements are inited with example with many functions, 'singlefunc'—with a single one. See, we take all the elements with a class and pass them to the function.
multifunc(document.querySelectorAll('.multifunc'));
Function runs 'for' loop and adds 'click' event listener. So the element should alert its index on click (beginning from 0). But in example with many function a wrong value is produced (because of closure, other answers also highlight the issue).
I think I should say also that it's not issue of single function/mutliple functions—it's a question of working with closures. You see, I can implement a working example WITH many closures: https://jsfiddle.net/pr7gqtdr/1/. I do basically the same thing that you do in a single-function handler, but every time call the new 'helper' function:
nodes[i].onclick = function (i) {
return function (e) {
alert(i);
};
}(i);
See, this (i) at the end is an immediate function call, so onclick gets a function with i variable set in closure.
But, the single function options is a bit better, because it's more memory efficient, I guess. Functions are objects. If you create many of them, you take more memory, in general. So, choosing from these, I'd stick with 'handler' function option.
The bad example creates a lot of event handlers; One per event. The good example create a single event handler and assigns it to all the events.
With the bad example, you've created lots of separate functions, instead of just one. That can be a lot of extra overhead and a lot of potential scope problems. These include closure issues such as an event only firing for the last item in the loop.
Additionally, the good example allows you to more easily unsubscribe the events because you have access to the original function pointer.
The good example is also just easier to read and understand. The loop is only used for creating the elements and binding their events; The handling of those events is done elsewhere.
As Soviut mentions, you are creating lots of event handlers in the bad example. Moreover, it is important to point out that the bad example functions refer to the same i variable, which means all of them will have the last value of nodes.length when they execute.
This is because a closure is created. You can read more about it in Closures.
first
I have the following code
function function_name () {
var list = $('li');
var active = $('li.active');
list.on('click', function(event) {
event.preventDefault();
list.removeClass('active');
// use this way
active = $(this);
// or this way
var newActive = $(this);
});
}
is it fast && better ? to assign a new value to global "active" variable
or declare a new variable "newActive" in the new the function?
and I am wondering whether there is a better way to filter the active list item from the list variable by it's class. I was thinking of using jQuery's .get() function but I'm not sure how to use it or what its return value would be.
You are asking two questions
1. Which is faster?
You are caring about the wrong thing. Changing the DOM (especially in visible ways) is going to be 1,000,000 times slower than assigning a variable. The difference between assigning a global and a local is so tiny that it would be impossible to measure it if you also change the DOM. And it will depend on which browser, browser version, OS, OS version, kind of processor and phase of the moon.
2. Which is better
In general it's considered bad to have global variables, so the more local is your state the better it is.
The reason is that with self-contained chunks that don't depend or pollute the global namespace it's easier to build bigger constructions by combining them.
When you use global state instead (like global variables or global functions) different chunks can collide on those globals and the end result is that the combination will not work (often in subtle ways).
The best is if you can avoid depending on or mutating the global state completely. This is often possible in Javascript using the pattern:
(function(){...})()
that creates a function and immediately calls it. The body ... can define its own variables and use them without interfering with the outside world.
Just a thought, $('li') returns all <li> in the page, same with $('li.active'), so if you have multiple <li> and <li class="active">, your code will remove all active items on clicking a li element.
Back to your question, I reckon it based on the scope of the variable, and what you want to do with it.
Using assignment, the value will be kept outside list.on('click', function(event) { ... });
While using declaration, the value will only be meaningful inside the function (it's not a good practice to have local variable the same name with global one)
If your code is:
var $list = $('li');
You can use jQuery's filter function:
var $active = $list.filter(".active")
https://api.jquery.com/filter/
The get function that you mention only accepts an index (see the docs http://api.jquery.com/get/) which would mean that you need to know which is the active <li>.
Check the performances by yourself: https://jsperf.com/ :-D That said, I guess there is no big differences, but more importantly, I have mercy on these "orphans" variables :'-( A little OOP would be more reliable:
// /my/UL.js (requires jquery.js)
var my = window.my || {};
my.UL = function (id) {
var me = this;
var ul = $('#' + id);
me.active = ul.children('.active');
ul.on('click', function (ev) {
// event delegation
if (ev.target.parentNode === this) {
me.handleClick(ev.target);
}
}
}
my.UL.prototype.handleClick = function (li) {
var me = this;
me.active.removeClass('active');
me.active = $(li);
me.active.addClass('active');
}
my.UL.prototype.getActive = function () {
// no DOM query
return this.active[0];
}
Usage:
var myUL1 = new my.UL('my-favorite-ul');
var myUL2 = new my.UL('a-crappy-one');
myUL1.getActive(); // the active list item or undefined
There are three things to notice here. First, using event delegation allows to add or remove list items without worrying about the click event. Then, a fresh active property is assigned to each instance of my.UL to avoid collisions. Finally, maintaining a reference to the active item avoids to query the DOM each time you want to get the item.
However, this is not a best practice, you can find many smarter solutions over the web. I'm just trying to widen your field of vision a little. This subject is indeed more complicated than you seem to think.
Anyway, keep in mind that there are plenty of possibilities to optimize your code. Take your time :-)
I am trying to display the markers one by one using setTimeOut but it is not working. here is my code:
function showOneByOne(arrayOfMarkersObj) {
for (u in arrayOfMarkersObj) {
setTimeout(function() {
arrayOfMarkersObj[u].setVisible(true);
}, 3000);
}
}
The problem is that It is showing only the last marker on the map and not all the markers. However if I put
arrayOfMarkersObj[u].setVisible(true);
outside of setTimeOut, It shows all markers.
Why is it happeneing?
Store the keys to an array (if you are solely on ECMA5 capable browsers you can use as suggested in comments the Object.keys() instead :
var keys = [];
for (u in arrayOfMarkersObj)
keys.push(u); //assuming arrayOfMarkersObj is an object not an array?
Now go one by one in your setTimeout:
var current = 0;
function reveal() {
arrayOfMarkersObj[keys[current++]].setVisible(true);
if (current < keys.length) setTimeout(reveal, 3000);
}
reveal();
If you want the first delayed switch the last line with:
setTimeout(reveal, 3000);
The reason why the example in the post doesn't work is because u is not available to setTimeout at the time it is called. The code invoked by the event setTimeout sets is invoked on the window object.
In order to make the var available you need to store it a "level up" typically the global scope or inside the wrapping function (by that = this for a reference as this becomes window, then use that inside setTimeout) to access it.
In JavaScript, the value of a variable in an inner scope is bound the scope where the variable is defined. Which means that the callback, when executed, will retrieve the value of u from the scope where u was defined, that is showOneByOne(). Therefore u will be equal to arrayOfMarkersObj.length -1 (the final value after the for cycle) for every execution of the callback.
One easy way to solve should be using forEach, even though it's not clear the need for different callbacks/timers for each element. You might as well use a single one as suggested in the answer by Ken - Abdias Software.
I have an object that generates HTML elements that are also connected with an array of the object, and let us say we have one instance of it. So as it creates the elements it also assigns the following event listener to a nested part of the element (the class being uploadDelete).
Now this event listener needs to call the delete method of the instance of the object that created it, with the value of i assigned at its creation. Because events are under Window, the instance needed to be passed to an anonymous function along with the i value.
This therefore assigns a very unique function to the event, and because the delete method will be destroying the element containing the listener I would like to remove it first; from what I've read it could cause leaks otherwise(?). I'm also using Strict Mode, so not arguments.callee.
file.display.getElementsByClassName('uploadDelete')[0].addEventListener('click',
(function(that,i){
return function() {
that.delete(i);
};
})(this,i), false);
I've tried many different things, but when I started having an anonymous function inside of a function inside of a function which is then called in the listener, I figured I should just ask on here. I might have a solution to the overall problem, changing other code, but it would still help if this could be answered.
Here is what I ended up doing, with the help of Norguard's answer. Since the uniqueness was stemming from an object called file, I just created a new property of file to store the function:
file.deleteFunction = (function(that,i){
return function() {
that.delete(i);
};
})(this,i);
file.display.getElementsByClassName('uploadDelete')[0].addEventListener('click',file.deleteFunction, false);
The delete function that is called then removes the event listener.
A relatively-painless way of doing this might be to create an object in the scope that's responsible for adding and deleting listeners, which builds an ID, serial or non, and will store whatever the listener is in an object, with that ID, returning the ID to whichever object/module requested it (or passing the anonymous function back to them).
// trivial example
var listeners = {},
i = 0,
add = function (context, func, closure) {
var enclosed = (function (closure) {
return function () { /* ... */; func(); };
}(closure)),
index = i;
context.addEventListener("...", enclosed, false);
listeners[index] = enclosed;
i += 1;
return index;
};
add will now add your listener, but will also store the function that you're passing into addEventListener into the listeners object.
If you need a reference to i, you've already got it in the closure, if you want it.
So now when you remove stuff, you can just look for the function saved at listeners[i].
An alternate, if you don't want to save a table full of these in one spot, for whatever reason, would be to catch the return statement, and instead of returning i, return the function;
// inside of your module
// I'm not usually crazy about `this`, without doing something particular with it,
// but hopefully it illustrates my point
this.cached_func = add(this.el, this.callback.bind(this), this.secret);
So now, when it comes time to delete everything, and you want to shut down your listener...
remove(this.cached_func);
All of that said, the leaks that you've read about are still possible, but the major culprit was IE6/7 (and earlier).
As people steer further from bad browsers, this becomes less important.
In fact, encouraging memory-dumps in IE6 is probably just a good way to encourage people to not use IE6.
This solution works, but I don't understand what the second return function() does?
for (var i = 0; i < photos.length; i ++) {
img.onclick = (function(photo) {
return function() {
hotLink(photo); //window.location = '/pics/user/' + photo.user_id;
};
})(photos[i]);
Also, why do I have to include the (photos[i]); at the end?
Before, I had this, and the onclick would always link to the last photo[i].
for (var i = 0; i < photos.length; i ++) {
img.onclick = function() {
window.location = 'pics/user/' + photo.user_id
};
}
When you do this (assuming there's a photo = photos[i] there that you left out in your question):
img.onclick = function() { window.location = 'pics/user/' + photo.user_id };
The variable photo inside the function refers to the same variable as photo outside the function. It's not a snapshot that gets the current value of the variable at the time you define the function; it's just a reference to the same variable. The surrounding loop changes the value of that variable on every iteration, but it doesn't create a new variable each time; it's reusing the same one. So all the functions you generate reference that exact same variable - the one and only photo.
By the time anyone actually clicks on the image and calls the function, the loop has long since terminated, and photo is gone from the main program's scope, but it's still out there in memory because all those functions still have references to it. And they will find it still pointing to the last item in the list, because that was the last thing assigned to it.
So you need to give each onclick function its very own variable that won't change once the function is created. The way to do that in Javascript, since it doesn't have block scope, is to call a function and pass the value in as a parameter. Function parameters and variables declared inside a function (as opposed to photo in the non-working example above, which is used inside the function but declared outside it) are created fresh on every function invocation. When photo is declared as a function parameter, each onclick gets its very own copy that nothing else can modify, so it still has the right value when someone finally clicks the image.
It might be clearer if it used a static function-generator function; there's really no reason to do the inline declare-and-call thing. You could declare this once, outside the loop:
function makeOnclick(somePhoto) {
return function() { hotlink(somePhoto); }
}
And then the loop body could do this:
img.onclick = makeOnclick(photo)
You're calling makeOnclick and passing it photo as a parameter. The makeOnclick function is declared far away, where it couldn't use photo directly even if you wanted it to; it can't see that variable at all. Instead, all it has is its local parameter somePhoto - which is created as a brand new variable every time you call makeOnclick. It's initialized with the value of photo at the point of the call, but it's just a copy, so when photo changes on the next loop iteration, that particular instance of somePhoto will stay the same. When the next iteration calls makeOnclick, it will create a new instance of somePhoto initialized to the new value of photo, and so on. So even though the inner function that makeOnClick is returning is inheriting the somePhoto var, that var was just created especially for that instance of makeOnClick; every one of those returned functions gets its own private somePhoto.
Your working code above is doing exactly the same thing in a slightly different way. Instead of declaring the makeOnclick function once, outside the loop, and calling it a bunch of times, it's redeclaring it every time through the loop as an anonymous function which it then calls immediately. This code:
img.onclick = (function(x) { blah(x); })(photo);
is the same as this:
function foo(x) { blah(x); }
img.onclick = foo(photo);
without having to give the function a name. In JavaScript in general, this:
(function (x,y,z) { doSomething(x,y,z); })(a,b,c);
is the same as this:
function callDoSomething(x,y,z) { doSomething(x,y,z); }
callDoSomething(a,b,c);
except the function has no name and is not saved anywhere; it goes away right after it's called.
So declaring the onclick-generator function every time through the loop and calling it immediately all at once is nice and concise, but not terribly efficient.
The returned function is a closure. When you're looping through like that i is updating on each loop until the end of the loop where you're stuck with the last image. Adding the self executing function and passing photo[i] in it will permanently enclose the current value within the returned function as photo.
Here is more information on closures: How do JavaScript closures work?
And here for more information on your current issue: JavaScript closure inside loops – simple practical example
Because a function invocation is the only way to create a new variable scope in JavaScript.
So you pass photos[i] to that function, and it becomes local to the scope of that invocation.
Then you also create the handler function in that same scope, so the handler is referencing that specific photo.
So in the end, if the loop iterates 10 times, you're invoking 10 functions, creating 10 new separate variable scopes, which reference each individual photo and create and return the handler from each separate scope.
These things are sometimes clearer if you don't inline the function like that.
for (var i = 0; i < photos.length; i ++) {
img.onclick = createHandler(photos[i]); // pass individual photos to createHandler
}
function createHandler(photo) {
// In here, the individual photo is referenced
// And we create (and return) a function that works with the given photo
return function() {
hotLink(photo); //window.location = '/pics/user/' + photo.user_id;
};
}
So if the loop runs for 10 iterations, we invoke createHandler() 10 times, each time passing an individual photo.
Because each function invocation creates a variable scope, and because we create the event handler inside each scope, what we end up with is all 10 functions being created in 10 variable scopes, each of which reference whatever photo was passed.
Without the per-iteration function invocation, all the handler functions are created in the same variable scope, which means they all share the same variables, which are likely being overwritten in each loop iteration.