I am trying to get the position of a moving div(animated using css3 animations) and for checking it continuously I am using a while(true) like below
function detectCollision(){
alert(document.getElementById("obstacle").style.left)
while(true){
var temp = getObstaclePosition();
var temp2 = getPlanePosition();
if(temp[0] <= temp2[0]+500){
document.getElementsByClassName("plane")[0].style.display = "none";
break;
}
}
}
The problem here is that after the first alert the page hangs. Moreover if I put an alert in the while loop then it keeps on popping up and the code works fine but not otherwise.
Let me know how I can fix this?
Instead of using a while (true), which is costly, you can use setInterval:
a = setInterval(function () {
var temp = getObstaclePosition();
var temp2 = getPlanePosition();
if(temp[0] <= temp2[0]+500){
document.getElementsByClassName("plane")[0].style.display = "none";
clearInterval(a);
}
}, 100);
The page does not render while you are inside that loop, and thus the position of the element will not change. This results in the loop never ending.
If you want to do something like this, you will have to be using a recursive setTimeout or a normal setInterval implementation.
With them, do one check per timeout.
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
JavaScript runs in one and the same thread, so if some loop occupies this with an infinite loop, the rest is not able to run anymore.
As an alternative to your loop, you could use setInterval, which repeatedly executes a function or code snippet:
setInterval(new function() {
// whatever
}, 100); // repeat every 100 ms, i.e. 10 times per second
Related
I want to scroll down the browser window in a loop in console. I want it so that every time a scroll down (x)px down I stop, do something and then scroll (x)px again and then stop etc. until the page with ends (its a very long one, I want to parse info from it).
But when I started I stumbled upon an issue, that the scrolling function is executed only once, after the loop ends.
let i = 0;
scrollDownTillEnd = () => {
for(i; i<100; i++) {
window.scrollBy(0, 1000);
};
scrollDownTillEnd();
(it is a simplified example, but the idea should be clear)
I put the code in the console, being on a page I want to scroll, and get then the value of i at the end of the loop and only one scroll down.
Please, explain me, why this piece of code behaves like this and how to make it work, as I mentioned before (in every loop it scrolls a little bit).
Thank you!
Let me help address a few issues going on here.
1) You have an infinite loop going on because you are not checking that i is less than 100 even though you are incrementing it each time. You need to check that i < 100 so that the loop will eventually end. In your loop, 0 will always be less than 100 so the loop will never end.
2) You have a syntax error in your example because you're not actually closing out the scrollDownTillEnd function with a curly brace before calling the function itself.
3) Lastly, as good practice, you need to reset your i variable to 0 each time so that we can run this piece of code over and over again. The way you have it set up in your example, since i will be equal to 100 at the end of the first run, the loop won't ever run again after that until you reset i to 0 again. The easiest way to do this is to just initialize i to a value of 0 each time you execute this loop.
Try something like this:
scrollDownTillEnd = () => {
for(let i = 0; i < 100; i++) {
window.scrollBy(0, 1000);
};
};
scrollDownTillEnd();
You can use setInterval() since for loop will executes only once
function scrollDownTillEnd(countryDropdownList)
{
let scrollingInterval = setInterval(function(){
window.scrollBy(0,1000)
// write your condition
if (window.scrollHeight > 10000)
{
clearInterval(scrollingInterval)
}
},100)
}
scrollDownTillEnd();
For this code:
var Obj={};
for(i=0;i<=5;i++){
var add = prompt("add stuff in me!");
var last = Obj.length;
Obj.last = "add";
}
console.log(Obj);
JS Bin insists that is is potentially an infinite loop and that it will terminate subsequently.
JSBin implements infinite loop protection by injecting code into your Javascript which times the loops (see here, at about the two-minute mark). Basically, if a loop takes more than a predefined time, it will exit it with the warning and continue the code.
Your problem here is that you are waiting for user input within your loop so, unless the user can enter those six values within the timeout threshold, it will consider the loop to be infinite. You can verify this by changing the user input line into:
var add = "x"; // prompt("add stuff in me!");
Running that in JSBin shows no issues, because the user input is not delaying the loop.
The fix for this is to add // noprotect to the line to stop JSBin from erroneously considering it infinite:
for(var i=0;i<=5;i++){ // noprotect
Added note: Although the linked video says the timeout is about a second, the code seems to disagree. It states that the threshold is only a tenth of a second:
/**
* Injected code in to user's code to **try** to protect against infinite
* loops cropping up in the code, and killing the browser. Returns true
* when the loops has been running for more than 100ms.
*/
loopProtect.protect = function protect(state) {
loopProtect.counters[state.line] = loopProtect.counters[state.line] || {};
var line = loopProtect.counters[state.line];
var now = (new Date()).getTime();
if (state.reset) {
line.time = now;
line.hit = 0;
line.last = 0;
}
line.hit++;
if ((now - line.time) > 100) {//} && line.hit !== line.last+1) {
// We've spent over 100ms on this loop... smells infinite.
loopProtect.hit(state.line);
// Returning true prevents the loop running again
return true;
}
line.last++;
return false;
};
I don't know if this is what JS Bin is detecting, but there is a potential infinite loop there.
The variable i is not declared, so it is by default a global variable. The loop body calls a function, which could change the value of i (e.g. i = 0;) so that it never reaches the end, and so the loop would be infinite.
Alternatively, i could be defined as a constant (const i;), which would prevent the value from changing, again making it an infinite loop.
I am trying to call a function from within a loop in a way that when the function finishes executing, the loop continues to the next iteration and calls it again. But instead the loop doesn't wait for the function to finish and instead calls 4 instances of the function and runs them at the same time! Should I put the whole function in the loop or is there to make the loop wait for the function to be executed? Thanks
for (var i=2; i<=4; i++){
galleryAnimation(i); //This is executed 3 times at once
}
function galleryAnimation(i){
$("#pic" + i).delay(delayTime).fadeIn(duration);
}
The function is being executed 3 times just like you requested, the problem is that both delay and fadeIn use timers: they set a timer in the future when the function will be executed and return immediately: they are non-blocking calls. So, in your case, because you're calling the function 3 times at, let's say, 0.0001s, 0.0002s, and 0.0003s, the three kick in at, let's say, 5.0001, 5.0002 and 5.0003.
What you had in mind were blocking calls to these functions. You expected the whole execution to stop until the animations were finished. This would stop the whole browser Javascript engine for the duration, meaning no other animation or user javascript interaction would be possible.
To solve it, you have to use callbacks. You can supply a function to fadeIn that will be called once the animation has completed:
http://api.jquery.com/fadeIn/
You can use queues to simulate the same on delay():
Callback to .delay()
Simplistic solution: Increase the timeout by a factor every time.
var i, factor,
duration = 250,
delayTime = 500;
for (i = 2, factor = 0; i <= 4; i++, factor++) {
galleryAnimation(i, factor);
}
function galleryAnimation(i, factor) {
$("#pic" + i).delay(factor * delayTime).fadeIn(duration);
}
This runs the same way your approach does, only the delays get longer every time.
Generic solution 1 - work with setInterval() to have your worker function (the one that does the fadeIn) called in predefined intervals:
var elements = $("#pic2,#pic3,#pic4").toArray(), // or any other way to select your elements
duration = 250,
delayTime = 500,
intervalId = setInterval(function () {
$(elements.shift()).fadeIn(duration);
if (elements.length === 0) {
clearInterval(intervalId);
}
}, delayTime);
Generic solution 2 - work with callbacks that are called when the previous animation finishes:
var elements = $("#pic2,#pic3,#pic4").toArray(), // or any other way to select your elements
duration = 250,
delayTime = 500,
next = function () {
$(elements.shift()).delay(delayTime).fadeIn(duration, next);
};
next(); // start the chain
one thing you can do, is to use an identifier (boolean) and then, in the loop, you test the identifier to decide if the loop can continue or stop.
For example,
function galleryAnimation(i, iBool){
$("#pic" + i).delay(delayTime).fadeIn(duration);
iBool = 0;
}
Then on the return;
for (var i=2; i<=4; i++){
galleryAnimation(i, iBool);
// If iBool = 0 then continue
// Else Break
}
that might be a solution, as the loop will need the returning value to determine the next step, to continue or break.
I came with my own solution that seemed to work perfectly, this is my code:
function fadeInAnimation(index){
$("#pic" + index).delay(delayTime).fadeIn(duration, function(){
photoIndex();
});
}
function photoIndex(){
index++;
fadeInAnimation(index);
}
fadeInAnimation(index);
});
I have realized that using loops is a really bad idea with things like this. This code will allow me to add as many images as I want just by renaming them in the folder rather than coding them in manually as callbacks for each photo.
Thanks for those who answered. Your suggestions are great and will definitely remember them in other applications like this one
Is there a way to make JavaScript print a counter continuously in the same place on the page?
for(var x=0; x<3000; x++){
document.write(x + '</br>');
document.body.innerHTML = "";
}
I want the number x to update and replace the previous number, however this code seems to wait until the loop is finished before showing a number (by then it is too late)
Is there a way to say, print number x, now wait 100ms, now clear and update in the same space the new value for x, and repeat?
(I know that the innerHTML is killing the whole page, for now all this pages needs to do is run a counter, so other elements are irrelevant. What I don't want is a printed list of all those numbers, and I need a delay)
Thanks!
The browser will not update the display while JavaScript is running. To make a timer happen you need to use setTimeout() or setInterval(). Also, avoid document.write() unless you have a good reason to use it (if you're not sure what makes a good reason then don't use it at all).
You want something like this:
<body>
<div id="counter"></div>
</body>
Then:
window.onload = function() {
var x = 0,
max = 3000,
ctr = document.getElementById("counter");
function incrementCounter() {
ctr.innerHTML = x;
if (x++ < max)
setTimeout(incrementCounter, 100);
}
incrementCounter();
}
Demo: http://jsfiddle.net/nnnnnn/v5hmE/
Note that the above updates only the contents of the "counter" div, so any other elements on your page would not be affected.
Homework assignment for you: Google everything you didn't understand in that code.
Yes! For that purpose I would recommend you two things:
To use a container (lets say a div) for that purpose:
and refer to it as document.getElementById('counter').innerHTML = x
To use javascript timers before updating.
Hope that helps,
...however this code seems to wait until the loop is finished before showing a number...
Don't use a for loop for this. You need a specific interval like you say. Use a function with a setTimeout and some recursion:
var x = 0;
var speed = 100;
function update() {
if (x <= 3000) {
setTimeout(function() {
// update DOM here
x++;
update();
}, speed);
} else {
return false;
}
}
Demo: http://jsfiddle.net/elclanrs/PRC9R/
You can change the interval to say 9 so it looks believable but goes faster.
x += 9; // instead of x++
How to set delay in for loop execution
for(i=0; i<=10;i++){
var s=i;//This line should execute for every 2 secs only
}
How to give loop delay in java script....
I dont want like below..I want without using setTimeout...
for(i=0; i<=10;i++){
setTimeout("setvalue()",2000); //This alert should display for every 2 secs only
}
function setvalue()
{
var s=i;
}
please help me...
Use setInterval()
var i = 0;
var interval = setInterval(function(){
setValue();
i += 1;
if(i == 10)
clearInterval(interval);
}, 2000);
There is no way to sleep for 2sec without freezing the whole browser. Javascript is single threaded.
You can't. JS runs in a single thread and any attempt to delay that thread will freeze the entire page. Using setTimeout is your only option.
EDIT: or setInterval; either way, there is no non-hairy way to express "halt execution here for x milliseconds."
Using setTimeout is inevitable, however, a recursive function might be a better solution for this one:
var i=0;
function recurs() {
i = s;
i++;
if (i <= 10) recurs();
}
recurs();
As others have stated, setTimeout can be used very well to handle these sorts of scenarios and setInterval could also be used but is discouraged by some.
You can even recursively call a function that has setTimeout built into it as mentioned in the MDN documentation of setInterval. The heading there mentions 'dangerous usage' but their solution to the danger is the block of code beneath.
There it mentions that to have a loop executing every x seconds (or milliseconds) then you can do the following and know for sure that the functions will only be executing one at a time and in-sequence:
(function loop(){
setTimeout(function(){
// logic here
// recurse
loop();
}, 1000); // repeat loop 1 second after this branch has completed
})();
And if you want it to only do that a limited number of times, then you can create a variable outside of the loop and only recursively execute if the count is smaller than the number of times you want to execute for. Such as this:
var count = 0;
(function loop() {
setTimeout(function() {
// logic
count++;
if (count < 10) {
loop();
}
}, 1000);
})();