setTimeout in for loop - javascript

Currently I am trying to make a little game maninly for myself for having fun while making it and using it, but i got stuck at a part.
I would like to make a memory game where the program generates a certain array filled with the names of the arrows that should change. So e.g.: left,left,up,down,right with this I would like to change the left arrow 1st only to green than back to normal then since the 2nd time it would happen twice since the 1st 2 elements of the array are "left".
So I have been trying to use setTimeout in JS and tried to look it up how to use it and managed to slowly advance but i kidna got lost in all of the explanations.
My current code changes all the arrows that are listed in the array green then changes them back to normal 1 by 1 (actually I can't see the 1st arrow changin at all but i assume it does just the setTimeout doesnt apply to it since the rest is changing).
for (var j = 0; j < narray.length; j++) {
var image = document.getElementById(narray[j]);
image.src = "arrow-"+narray[j]+"-good.png";
function(j){
sesetTimeout(function(){
var image2 = document.getElementById(narray[j]);
image2.src = "arrow-"+narray[j]+".png";
}, j*1000);
})(j);
I know it is really messy but I have totally got lost in the tutorials I have tried to learn from. So if anyone could help me I would be really greatful.
Thanks in advance!

Here's what I think will work.
k=0;
for (var j = 0; j < narray.length; j++) {
var image = document.getElementById(narray[j]);
image.src = "arrow-"+narray[j]+"-good.png";
setTimeout(function(){
var image2 = document.getElementById(narray[k]);
image2.src = "arrow-"+narray[k]+".png";
k++;
}, j*1000+500);
}
So besides the typos, there's an issue with using "j" from the for loop in the timeout functions because they run later. So we introduce "k" to keep track of how many of them we've done. So k will be incremented each time, and here it's a global variable, so as each timeout function actually runs, k will be a different number, and will increment k to be ready for the next one that will be called.

What if you don't use a for loop and you call the function recursive, something like this:
function doSomething(j,l){
if(j>=l) return 'done';
setTimeout(function(){
console.log('step: ' + j + ' from: ' + l);
// add your code here :)
}, j*1000);
doSomething(++j,l);
}
doSomething(0,narray.length); // start with 0 and the length of the array

Related

Arrays are causing me problems

So. Started arrays. Yeah went as well as the loops did. And as a result, I need help.
/*jshint multistr:true */
var text = "Yo yo yo, what's / good fam. My name is / Caleb, my dude.";
var myName = "Caleb"
var hits = []
for(var i = 0; i >= text.length; i++){
if(text[i] === 'C') {
}
for(var j = i; i <= i + myName.length; i++){
}
}
That is the exact code that I have. Now, What it needs to do is search for my name within the confines of the text string. Only problem is that its saying that "It looks like your second 'for' loop isn't pushing values to the hits array. Make sure it's working properly and that myName's text appears somewhere in the text variable." This is a CodeAcademy project. I'm just not understanding. If someone could help me with this, I would really appreciate it.
Thanks!
First of all make sure you have all the semicolons right. Also, add some action in case the loop gets a result!
Also, i don't think you have defined var j, did you?
Finally - if it's asking u to push some values into hits array, then use this push method:
hits.push();
To help u i'd need deeper understanding of the task itself. what did u have to do, what were u starting with?
Edit:
var myName = "Caleb"; // define myName before text so it can be used in text
var text = "Yo yo yo, what's / good fam. My name is / "+myName+", my dude."; // define text and use myName variable between two strings, connected with +
var hits = []; // define hits array
for(var i = 0; i < text.length; i++) { //start loop, make sure second parameter is not infinite or it would crash your browser
if(text[i] === 'C') { // if found i that corresponds with 'C'
var letterLocation = i; // set variable letterLocation with value of 'C' position
hits.push(i); // add the location number to hits array with .push method
};
};
console.log(hits); // display hits array in console
Here's some working code for you, just follow the task and change whatever is necessary - hope it helps.
Generally - i changed the order of variables, so that u can use myName in text, also made the for loop print out the position of letter C and push this value into the hits array. Is that what u meant?

how to download multiple audio files using download attribute?

i was wondering if i can download all audio files from google word pronunciation
i came up with a solution that actually works
i created an html page with the following code
<a id="mylink" href='//ssl.gstatic.com/dictionary/static/sounds/de/0/word.mp3' download='word.mp3'>download audio "word"</a>
now if you click the above link , the browser will start downloading the audio file
and if you change word.mp3 to something else and click it again ,
it will start downloading the new word;
the problem is I tried to download the whole dictionary in mp3 format.
so i came up with the following javascript
var words=['cat','fish','police','office','ball'];//the whole dictioany.....
for(var z in words )
setTimeout(function(){
var lin=document.querySelector("a");//gets the above link
lin.href="//ssl.gstatic.com/dictionary/static/sounds/de/0/"+a[z]+".mp3";//changes link href to each of the array "words"
lin.download=a[z]+".mp3";//changes the file name to current word
lin.click();//after clicking this link , all downloads start at the same time
},1000)//even it setup to fire after 1 second
//all the downloads start at same time
the biggest problem is that only audio file downloaded is the last one "ball"
and it's downloaded multiple times
any solution is appreciated and thanks in advance
here is the example on jsfiddle click
You can't use a setTimeout() in a loop, as the loop will execute faster than the timeout. Thus, the final result will be ran for each event in the loop (a[z] will call a[4] five times). To get around this, you'll need to slightly modify your for loop, and not use a timeout:
var a = ['cat', 'fish', 'police', 'office', 'ball'];
for (var z = 0; z < a.length; z++) {
var l = document.querySelector("a");
l.href = "//ssl.gstatic.com/dictionary/static/sounds/de/0/" + a[z] + ".mp3";
l.download = a[z] + ".mp3";
l.click();
}
I've created an updated fiddle showcasing this here.
Hope this helps!
The problems with your code are:
The setTimeout is executed within the loop at nearly the same time. So that is why the function is also executed at the same time. Think of having ten egg timers that you all activate at the same time. They will also all ring at the same time.
The function triggered by setTmeout uses the variable z declared outside the function. It does not use the value of z at the time when setTimeout is executed, but at the time the function is executed. All instances of the function access the same variable, so they all use the value of z during the last loop.
Instead of having a loop, use setInterval to execute a function at a given interval and use a counter variable so that a different variable is used at each time the function is executed.
function run()
{
var words=['cat','fish','police','office','ball'];
var counter = 0;
// Setup IntervalFunction to run every 2 seconds
var interval = setInterval(IntervalFunction, 2000);
function IntervalFunction()
{
// Download word
downloadWord(words[counter]);
// Increase counter
counter++;
// When counter is beyond array, stop IntervalFunction from running
if(counter >= words.length)
{
clearInterval(interval);
}
}
}
function downloadWord(word)
{
var lin = document.querySelector("a");
lin.href = "https://ssl.gstatic.com/dictionary/static/sounds/de/0/" + word + ".mp3";
lin.download = word + ".mp3";
lin.click();
}

javascript: var i is not defined? (clearly defined)

WHAT I WANT TO HAPPEN
So what I want to happen is function partA() to click button [z] every 2 seconds. The button that is being clicked should change, because the script is a looping script, so for instance. The first loop, it would click button 1, then button 2, then button 3, because var z = 1 + i++. Is this possible? z is supposed to equal the number 1, plus the loop number. This should loop as long as variable i is less than 50.
WHAT IS HAPPENING
It works properly, looping and all, if I test the script without variable z. However, without variable z, I have to manually change the number that would equal z, which is painstaking, and annoying.
var z = 1 + i++
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
}
Should i++ be defined another way? The error I'm getting when running the script in console is:
Uncaught ReferenceError: i is not defined (...)
at :2:13
at Object.InjectedScript._evaluateOn (:878:140)
at Object.InjectedScript._evaluateAndWrap (:811:34)
at Object.InjectedScript.evaluate (:667:21)
There's a couple of suggestions I could advise with your code so I'll try and address each one individually.
Firstly define your function outside of your loop. If you would like to know the reasons behind this please read: Don't make functions within a loop
Secondly you should really declare i as a variable to set the scope to which it applies. Some good information on this is at: Declaring variables without var keyword
Thirdly when you run your loop you could run the code inside an IIFE. The reason for this is when you run setInterval, by the time it runs i will actually be 3 (or the last number of your loop). This is due to the asynchronous nature of setInterval, and that the reference to i is bound to the function, not the value of i.
Example
for(var i=0;i<3;i++) {
(function(i) {
setInterval(clickButton(i), 2000);
})(i)
}
function clickButton(idx) {
return function() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[idx].click();
}
}
JSBin Demo
http://jsbin.com/harigewuze/edit?html,js,output
Why are you trying to define z outside the loop? Just use i.
for (var i = 0; i < 50; i++) {
...
document.getElementsByTagName('button')[i].click();
}
without changing your code too much I would write it like this...
you know its looping 50 times, you know i is incrementing from 0 to 49, use i to change the button name and you don't need z...
for(i=0;i<50;i++) {
setInterval(partA, 2000);
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[i + 1].click();
}
}
1) This is how you want your code to look like :
var z;
for(i=0;i<50;i++) {
z=i;
setInterval(partA, 2000);
}
function partA() {
buttons = document.getElementsByTagName('button');
document.getElementsByTagName('button')[z].click();
}
2) Unfortunately, in javascript you have a problem with this code due to the fact of scopes. My recommendation is to read this link first http://www.mennovanslooten.nl/blog/post/62 and understand how it works.
If you did understand it, then thumb up..you just promoted yourself to a higher level in javascript ;)
3) If you are still having issues, post it on JSFiddle

performing long loop

i want to perform a loop that writes strings in a div without overloading. I have got a list of names in an global array called names. The array is filled with about 2500 names. Now i want to write the names in a div using ajax. But when i want to loop the names, the script is kinda overloading and stops with an alert of the client. This is my loop:
for(var i = 0; i < names.length; i++){
document.getElementById('div').innerHTML += names[i] + "<br/>";
}
I also tried to interlace the loop in smaller steps like 100 (because i thought like that the loop wouldnt overload). I also tried it with window.setTimeout("function(i)",0); with the param i, that steps 100 each time the function gets called, until i am at the length of the array names.
I know there is an easy way. But i can't find that way..... would be pleased by getting help.
Thanks
You can code it like:
document.getElementById('div').innerHTML = names.join('<br/>');
This will set the inner html in single instruction, solving the load issue.
try it this way:
var content = '';
for(var i = 0, n_length = names.length; i < n_length; i++) {
content += names[i] + "<br/>";
}
document.getElementById('div').innerHTML += content; // if the previous content should remain there
Please note that its faster, to store the abort value of a loop. Otherwise it would read the length-property of your array for each iteration of your loop (2500 x).
Also note that DOM-Manipulation is very verys slow, so its smart to reduce it to the lowest level possible. Better build your content separately and write it to the DOM once for all.

Sequentially firing multiple random timeouts in JavaScript

I know at first glance (due to the title) this looks like one of the "Did you try searching Google before posting?" questions, but I can't seem to find an answer for the specific issue I'm experiencing. Sorry if I'm a noob.... still learning :)
I need to simulate a pause in javascript, but the setTimeout(function_call, timeout) function is not working for me. Reason being... when that setTimeout function is called, it then makes the function call asynchronously.
A little background:
I'm trying to simulate text being typed into a div at randomly timed intervals. I want it to appear as if a person is actually typing a message while the user is viewing the page. Since the timeout is a random interval and the function call is made asynchronously, the text ends up being printed in a random order.
Here is a snippet of what I have thus far:
typeString: function(s)
{
for(var i=0;i<s.length;i++)
{
var c = s.charAt(i);
var temp = setTimeout("MessageType.typeChar('" + c + "')", this.genRandomTime());
}
}
Thanks in advance for your help.
CJAM
UPDATE: By adding the timer delay to a varialbe, it enabled me to offset timeOut for the asynchronous calls. Thank you all for your quick responses. Here is the updated code:
typeString: function(s)
{
var delay = 0;
for(var i=0;i<s.length;i++)
{
var c = s.charAt(i);
setTimeout("GoogleTyper.typeChar('"+c+"')", delay += this.genRandomTime());
}
}
Have you tried cumulatively setting the timeout? Stick a variable outside of your loop and initialize it to 0. Let's call it timeout for now. Add a random amount of time to this variable at the beginning of each iteration of your loop, and make the timeout work off of that. This way, you are ensured that functions are being called in order.
Your problem is you are using one all your times are delayed starting from now - the next timer needs to be fired after the previous. Simply add the previous timer delay to the new timer.
typeString: function(s)
{
var delay = 0;
for(var i=0;i<s.length;i++)
{
var c = s.charAt(i);
delay = delay + this.genRandomTime();
var temp = setTimeout("MessageType.typeChar('" + c + "')", delay );
}
}
Instead of passing to each timer event that character to be displayed, let each event handler grab the next character off of a queue (array, list whatever), so the order is maintained.

Categories

Resources