Adding delay in few items - javascript

I just got a little problem. So I've got array of div names and I want to add them class for half a second and then remove in order they are set. So first shows after a second and disappears after half a second, and next after second etc. I loop through array and nothing really happens :/
Please help me with this function :/
function showAndRepeat(){
for(var z=0;z<clickNext.length;z++){
console.log(colors[clickNext[z]]);
setTimeout(function(){$(colors[clickNext[z]]).addClass(colorNames[clickNext[z]])},1000);
setTimeout(function(){$(colors[clickNext[z]]).removeClass(colorNames[clickNext[z]])},1500);
}
}

Assuming the jQuery code is working fine.
Try this:
function showAndRepeat(){
for(var z=0;z<clickNext.length;z++){
console.log(colors[clickNext[z]]);
(function(zee){
setTimeout(function(){$(colors[clickNext[zee]]).addClass(colorNames[clickNext[zee]])},1000);
setTimeout(function(){$(colors[clickNext[zee]]).removeClass(colorNames[clickNext[zee]])},1500);
})(z);
}
}
Simply, create a closure.
for loop is a sync operation whereas setTimeout is an async. therefore by the time setTimeout executes, the for loop have already ran and the latest value of z is fed into setTimeout call.

Related

Do eventlisteners callback functions go into callback queue?

I think depending on my understand that callback functions are placed in the callback queue and don't execute until callstack is empty, so in the following code, why does the callback function of the event listener is executed on button clicking while console.log(index) is running ? Should the background color changed after the execution of all functions console.log() existed in the callstack first?
<button>Click me</button>
<script>
for (let index = 0; index < 100000; index++) {
console.log(index)
}
document.querySelector('button').addEventListener('click',()=>{
document.querySelector('body').style.backgroundColor = 'red'
})
</script>
Your code is all sync.
What will happen above is the thread will be blocked until for-loop ends.
then you’ll create a arrow function -that will capture global ctx- and be saved in memory
Code will pass the ref of this fn to addeventlistern which will push fn ref to list of callbacks to be called once event is emitted
to summarize yes button click will trigger bg.
In other words, until for-loop finish you didn’t event reach spot where you register callback so it won’t trigger (but a forloop of 10k will probably finish in less than ~10ms) after that you will register Cb and be good to go
Yes, because the for loop is sync, so even if it's a loop of 100 thousand, they all start to run at the same time, so the rest of the code will also be executed and even before all the console log() are executed.
An example to demonstrate that, I tried something similar once by putting a settimeout in a for loop to make a delay between each loop count like this
for (let i=0; i<31; i++){
setTimeout(()=>console.log(i), 1000)
}
console.log('finished')
This should run console.log every 1 second, but the actual behavior is that the 30 loop counts start to run together and are executed in 1 second along with last console.log().
So, knowing that, I modified it to
for (let i=0; i<31; i++){
setTimeout(()=>console.log(i),
1000*(i+1))
}
console.log('finished')
Now after this modification, the loop will run every 1 second as we increased the timeout by 1 extra second for each loop count, which confirms that the loop counts all start at the same time, but the last console.log('finish') will run before the loop even starts logging as the loop is a sync code which won't be awaited to finish before the next line of code runs.
I hope this helps
As I see you're asking the wrong question,
if the event listener goes to the callback queue or not
( actually I believe it goes to the callback queue ) won't change the behavior of your code,
as in all cases the for loop must complete before even adding the event listener to the button element itself ( adding the listener not running it through clicking ) .
thus if the event listener added to the button so the for loop must be completed its work and that's what's happening already.
but the behavior you see is happening because the for loop has completed its work but the browser hasn't completed its work logging the numbers ( rendering them on the screen ).
I hope it's clear enough now.
for better understanding you can :
Enable timestamps in your devtools console.
Add another console.log inside your listener itself.
Use performance.now() or Date.now() inside your logs to grasp it more when everything is running.
Use the devtools debugger to run the code step by step.

jQuery sleep in "each" iteration, and call function when iteration is done

I want to go through each element with a certain class, and show them one by one, but will a random delay between them.
The tricky part is, that I want to do it in a linear fashion, so I don't start off a new thread for each element, since then the elements will be shown randomly (because the delay is also random).
After this is done, I would like to run another part of the code.
What i have now looks like this, but you can see that the delay is set to a fixed amount (in order not to mess up the order of the elements)
jQuery('.myclass').each(function(index) {
jQuery(this).delay(1000 * index).fadeIn(0);
}).promise().done(function() {
//run code that has to run when the iteration is finished
});
Is there another way to achieve this, where I might not even need to use a promise, and a callback for when the iteration should be done?
A more linear approach, where I would "sleep" inbetween iteration, like this?
jQuery('.myclass').each(function(index) {
jQuery(this).show();
//sleep somehow for 1 or 2 seconds
})
//run code that has to run when the iteration is finished

Javascript: Array not shifting, multiple setTimeout functions (JSON)

I'm really stuck on this javascript question!
So I'm making a web page that will be completely animated (so it can be used for display for example in a television). That animation will be configurable by the user (stored in a database).
Right now, I've already made the code to store the configuration and to get the configuration (I do an AJAX call and save the configuration in an array of json objects) and everything is as it should be.
The problem is in the animation in which I go through the array and use setTimeout function to create animations. To iterate through the array I rotate it
(I use array.push(array.shift()) according to the answer here).
The first time the intervalmaster function is used, everything goes according to plan, but when the function is called again I need to rotate the array once more (because of the last animation) and the array just doesn't rotate!
Bellow I've left a portion of the code that I'm using that reproduces the problem I'm getting. I've also added the array jsonanima with some possible values (In reality the array is probably much bigger and with higher values).
I really don't understand what is happening, I've also considered that this could be a problem of the multiple setTimeout functions because I've read somewhere (couldn't find the link, sorry!) that is not really advised to use multiple setTimeout.
If that's the case is there any other way to do this?
Thank you in advance!
EDIT: Thanks to the comment from mplungjan I've realized that if change the console.log(jsonanimate) to console.log(JSON.stringfy(jsonanima)) it outputs the correct values (the json array rotated). This got me even more confused! Why do I need to JSON.stringfy to get the array in the correct order?!
Anyway, can't test this with the full code now as I'm not in the office, tomorrow I'll give more feedback. Thank you mplungjan.
EDIT2: Finally solved my problem! So the thing was the call to the function recursivegroup (recursivegroup(0);), this call was made before I rotated the array, so when restarting the animation the array would still have the incorrect values and every sub-sequential value was wrong.
A special thanks to mplungjan and trincot for the comments that helped me debug this problem.
Bellow I leave the code corrected so anybody with the same problem can check it out.
jsonanima=[{"VD":5,"A":10,"diff":0.25},{"L":7,"IE":8,"diff":0.25}];
function intervalmaster(flag){
function recursivegroup(index)
{
if(index==0)
{
//animateeach(jsonanima,0);
}
setTimeout(function(){
//HERE IT WORKS
jsonanima.push(jsonanima.shift());
console.log(JSON.stringify(jsonanima));
//animateeach(jsonanima,0);
//removed the if statement, since it was irrelevant as mplungjan noted
recursivegroup(index+1);
},(jsonanima[0]['diff'])*60*1000);
}
//Changed this
//recursivegroup(0);
var mastertime=0;
for(var key in jsonanima)
{
mastertime+=(jsonanima[key]['diff']);
}
console.log(mastertime,flag);
console.log(JSON.stringify(jsonanima));
if(flag==true)
{
jsonanima.push(jsonanima.shift());
console.log(JSON.stringify(jsonanima));
}
//changed to here
recursivegroup(0);
masterinterval=setTimeout(function(){intervalmaster(true)},mastertime*60*1000);
}
intervalmaster(false);

JS Loop is looping and crashing browser?

for (i=0;i<channelName.length;i++) {
if (channelName[i]=="channel"||channelName[i]=="user") {
checkUserDuplicate(channelName[i]);
}
}
This loop is causing an "out of memory" crash in all browsers. can anyone see why? It seems to be crashing at the IF statement and then causing an infinite loop somehow.
If you're wondering what the code does, it finds the keywords "channel" and "user" in an array of undefined length, then gets the string at the next position.
Any help would be much appreciated as I have been sitting here puzzled for 2 hours.
EDIT: channelName is a URL like http://www.youtube.com/user/username
this is the function:
function checkUserDuplicate(channelName) {
var idarray=[];match=0;$('.channels').each(function(){idarray.push(this.id)});
for (i=0;i<idarray.length;i++) {
var current=channelName.toLowerCase();compare=idarray[i].toLowerCase();
if (current==compare) {callError(channelName+" already exists in this collection");match=1;}
} if (match==0) {checkExists(channelName);}
}
It's a mess :)
In your for loop, if you don't specify var i = 0;, it's globally accessible then. And in your other functions, you may modify the value of i and cause it doesn't increment as expected ends up with an infinite loop.
Sorry I didn't read the code since it's pretty messy, but that could be the reason
In the checkUserDuplicate function it counts the amount of DIVs within a scope of classes. If there is no classes or DIVs the count is 0, and passed on to the for loop and creates a recursive loop.

how to make sure one javascript function get caled after another function

I am new to javascript and don't know whether its using stack for keeping trace of function calling .
This is the code i got stuck with
function bounce(nIdx,bMulti)
{
idDivread.style.display='';
initBounceMgr();
cBounceMgr.bounce(document.all.KnlTbl.rows[nIdx].cells[0].procName,bMulti);
readKill();
}
function readKill()
{
idDivread.style.display='none';
}
This bounce function is called by onclick event and i want to show a div as it has image of wait symbol. And this is working but as i want to remove this wait symbol after function call is done i applied this readKill function. But then that image is not coming at all.
Seems that this function get called before these two functions.
What to do to make sure that readkill function get executed after this two function.
They are being called in the order you would expect. The problem probably comes from the fact that if bounce is an animation or similar it probably returns immediately and does the animation asynchronously. So what it is in fact doing is showing the div, starting the bounce, then hiding the div and in the hidden div doing your bounce animation.
Usually methods that run like this will accept a callback parameter. That is a method that is called after they have finished doing what they want. In this case you would pass readKill in as the callback function instead of calling it directly.
I'm not sure what the cBounceMgr object is though so it is impossible to give you exact syntax to use.

Categories

Resources