setTimeout inside while loop - javascript

I've searched for how to use setTimeOut with for loops, but there isn't a lot on how to use it with while loops, and I don't see why there should be much difference anyway. I've written a few variations of the following code, but this loop seems to crash the browser:
while(src == '')
{
(function(){
setTimeout(function(){
src = $('#currentImage').val();
$("#img_"+imgIdx).attr('src',src);
}, 500);
});
}
Why?
Basically I have an image created dynamically whose source attribute takes time to load at times, so before I can display it, I need to keep checking whether it's loaded or not, and only when its path is available in $('#currentImage'), then do I display it.
This code worked fine before I used a while loop, and when I directly did
setTimeout(function(){
src = $('#currentImage').val();
$("#img_"+imgIdx).attr('src',src);
}, 3000);
But I don't want to have to make the user wait 3 seconds if the loading might be done faster, hence I put the setTimeOut in a while loop and shorted its interval, so that I only check for the loaded path every half second. What's wrong with that?

The while loop is creating trouble, like jrdn is pointing out. Perhaps you can combine both the setInterval and setTimeout and once the src is filled, clear the interval. I placed some sample code here to help, but am not sure if it completely fits your goal:
var src = '';
var intervalId = window.setInterval(
function () {
if (src == '') {
setTimeout(function () {
//src = $('#currentImage').val();
//$("#img_" + imgIdx).attr('src', src);
src = 'filled';
console.log('Changing source...');
clearInterval(intervalId);
}, 500);
}
console.log('on interval...');
}, 100);
console.log('stopped checking.');
Hope this helps.

The problem is probably that you're not checking every half second.
setTimeout schedules a function to run at a future time, but it doesn't block, it just runs later. So, in your while loop you're scheduling those functions to run just as fast as it can iterate through the while loop, so you're probably creating tons of them.
If you actually want to check every half second, use setInterval without a loop instead.

Thanks everyone - all the suggestions helped. In the end I used setInterval as follows:
var timer;
// code generating dynamic image index and doing ajax, etc
var checker = function() {
var src = $('#currentImage').val();
if(src !== '') {
$('#img_' + imgIdx).attr('src', src);
clearInterval(timer);
}
};
timer = setInterval(checker, 500);

Related

Display a series of colors sequencially with JavaScript

I need to display a series of RGB colors inside my ASP.NET web page. I was hoping to accomplish this using an ASP Update Panel but the update has to take place in sequence without the user intervention, every 4 or 5 seconds.
My initial JavaScript code looks like this :
document.getElementById('div').style.backgroundColor = "rgb(0,0,255)";
Problem is getting the next RGB color combination to display.
I experimented with a wait 'loop' found here in another post :
wait(7000); //7 seconds in milliseconds
function wait(ms) {
var start = new Date().getTime();
var end = start;
while (end < start + ms) {
end = new Date().getTime();
}
}
Problem is that, it does not work. I tried with :
document.getElementById('fondRGB').style.backgroundColor = "rgb(0,0,255)";
wait(7000);
document.getElementById('fondRGB').style.backgroundColor = "rgb(128,128,128)";
wait(7000);
document.getElementById('fondRGB').style.backgroundColor = "rgb(0,0,0)";
but only the very first rgb color is ever honored?
running a blocking while loop in javascript is a really bad idea. There is only one thread so if you do that the user will not be able to interact with your application until your while loop is complete.
A better solution is to use setTimeout to run the timer asynchronously and call the callback when the timer is complete.
var el = document.getElementById('fondRGB')
function wait(ms, callback) {
setTimeout(callback, ms)
}
wait(7000, function(){
el.style.backgroundColor = "rgb(0,0,255)"
})
wait(14000, function(){
el.style.backgroundColor = "rgb(128,128,128)"
})
wait(21000, function(){
el.style.backgroundColor = "rgb(0,0,0)"
})
So even if that did work it wouldn't be what you want since the wait function is attempting to block the only execution thread which would just make the whole browser hang. The wait method you are looking for is called setTimeout and it works a little different than you are probably used to.
setTimout lets you specify a function and an amount of milliseconds before it will execute that function so in your case if you want to accomplish changing the background color every 7 seconds you would probably do something like this:
var colors = ['rgb(0,0,255)', 'rgb(128,128,128)', 'rgb(0,0,0)'];
for (var i = 0; i < colors.length; i++) {
setTimeout(function(color) {
document.getElementById('fondRGB').style.backgroundColor = color;
}.bind(null, colors[i]), i * 7000);
}
Sorry that the code got a little complex, look up closures if you are wondering why the .bind part is necessary (if you are not already familiar).

Node.js : How to run a special function as server starts as a initialization?

I use Express framework, I have this function and I want to run it in intervals since server starts:
setTimeout(function () {
console.log('timeout completed');
}, 1000);
so i put this piece of code to the initial file of Express.js Framework called App.js but it only runs twice, where is the problem and how could I fix it?
The setTimeout function runs only once when that amount of time is completed,
here in your case it is 1s(1000ms).
Instead you may want to use setInterval which does the same thing except that it doesn't stop until you tell it so.
Here is an example :
var max = 3;
var i = 0;
var timer = setInterval(function(){
if(i === max){
// stop the timer from looping.
clearInterval(timer);
}else{
i++;
}
},1000);
Looks like you are describing a cron sort of job, why don't you use any of the many node crons modules instead.
https://www.npmjs.com/package/node-cron
Check that out, pretty straight forward.

Call function when <audio> is at specific time

I am currently doing some fun website, which requires audio cues (I assume that's the name?). I want the site to do something, when the song has been played for exactly X amount of time.
I can easily get the current time using element.currentTime, but I have no clue how to say: when element.currentTime == 5.2, runFunction() - If you know what I mean. Is there some kind of way this could be done? My current test code:
<----AUDIO WILL START PLAYING---->
http://jsfiddle.net/jfL4mcnh/
$("<audio id='audioElement'>").appendTo("body");
$("#audioElement").attr("src", "http://mp3ornot.com/songs/1B.mp3").attr("autoplay", "autoplay");
setInterval(function() {
//for some reason, $("#audioElement").currentTime won't work, so we're going old fashion
time = document.getElementById("audioElement").currentTime;
console.log(time);
}, 1000);
Also, I forgot to say this, I cannot do a setTimeout() and hit at the exact moment I want in milliseconds, because the audio can take some extra time to load, while the actual code runs exactly when it has been "seen", if you know what I mean. So no countdown. I need to be exact here.
If you need greater resolution than ontimeupdate provides, you can use a setInterval instead.
Live Demo (sound and alert box only!):
$("<audio id='audioElement'>").appendTo("body");
$("#audioElement").attr("src", "http://mp3ornot.com/songs/1B.mp3").attr("autoplay", "autoplay");
var triggered = false;
var ael = document.getElementById("audioElement");
var interval = setInterval(function(){
console.log(ael.currentTime);
if (!triggered && ael.currentTime >= 5.2) {
triggered = true;
alert("5.2 seconds reached");
}
if (ael.ended) clearInterval(interval);
}, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
JSFiddle Version: http://jsfiddle.net/jfL4mcnh/15/
Well, I have done it myself.. It seems.
http://jsfiddle.net/jfL4mcnh/13/
$("#audioElement").bind("timeupdate", function() {
var currentTime = parseInt(this.currentTime, 10);
if(currentTime == 2) {
console.log("2 seconds in");
$(this).unbind("timeupdate");
}
});
You can bind timeupdate to it, then unbind it (apparently it runs the code 4 times, so I have to unbind it).
EDIT: Nope, it doesn't update fast enough to make it perfect on point. It increments each ~300ms it seems.
See this jsfiddle here
I've added the following line to the JavaScript setInterval() function:
if (time > 5.2) {
myFunction();
}
myFunction() does a console.log, which you'll see in the console.
The reason I used > rather than === is that the time reported is never precise due to fluctuations in processing. A Boolean in the condition would solve this problem:
triggered = false;
if (time > 5.2 && !triggered) {
triggered = true;
myFunction();
}

setInterval works then hangs browser javascript

I'm wanting to animate an element using setInterval. I've put my code into an object with 2 functions one to initialize and one to animate using setInterval. When I try to run the code the animation works once then causes the browser to hang. The only thing I can think of is an infinite loop being created somewhere however I can't see anywhere in my code that would cause this.
What is causing the browser to crash, how can this be overcome ?
<div id='box' style='position:absolute;height:100px;width:100px;background-color:#44e'>box</div>
<script>
var box = {
init : function(elemId) {
box.elem = document.getElementById(elemId);
box.timer = setInterval;
box.tick = 0;
box.animate();
},
animate: function() {
if(box.tick < 100) {
box.elem.style.top = box.tick +'px';
box.elem.style.left = box.tick +'px';
box.tick++;
} else {
clearInterval(box.timer);
}
var timer = setInterval(box.animate, 50)
}
}
box.init('box');
</script>
setInterval sets up a function that will be called repeatedly by the browser until you cancel the interval timer. Your code isn't doing that, because the only call to clearInterval is using box.timer, which is never set to a timer handle (the return value from setInterval). So you end up scheduling thousands of calls (a new series every time animate is called) and bringing the browser to its kneeds.
At the very least, this:
var timer = setInterval(box.animate, 50)
should probably be:
box.timer = setInterval(box.animate, 50);
Or you may want setTimeout (which schedules only one call back).

Timeout in Jquery to update the Dom?

Let's say I want to change the image source onClick and do some calculations. Whats happening right now is that the source changes when the the function exits. (Dom is busy?)
How can I make it so that the image source updates right away and then the function proceeds to the while loop?
HTML:
<img src="http://goo.gl/l55G2P" id="ImageSrc">
JS:
$( "#ImageSrc" ).click(function() {
new_imgsrc="http://goo.gl/wBhyee";
$("#ImageSrc").attr('src',new_imgsrc);
test = 0
do {
test = test + 1;
console.log(test);
} while (test != 50000);
});
Here's a JSFiddle.
Not sure I understand you correctly but you could use a timeout:
setTimeout(function() {
//while loop here
}, 1000);
Where 1000 means 1 second. You could shrink this value so it doesn't wait as long.
As click() has no callback for onComplete I am not sure of a better way to achieve this.
This problem is actually a bit trickier than just setting a timeout, if you want to do it right.
The problem with setting is a timeout is that the timeout has to be large enough for the image to load. If the image isn't loaded within the timeout, it'll still have to wait for the loop.
What you have to do instead is actually give it a chance to update the DOM in between each step. To do this, you need to set up a timeout (or interval, but I prefer the timeout method since you have better control) that triggers every 0ms (basically, as fast as possible). However, since these are all timeouts, it has a chance to update the DOM in between two of these when it is ready.
console.clear();
$( "#ImageSrc" ).click(function() {
loading_imgsrc="http://goo.gl/wBhyee";
$("#ImageSrc").attr('src',loading_imgsrc);
console.log("changed");
doTest(0);
});
function doTest(test) {
test = test + 1;
console.log(test);
if (test < 1000) {
setTimeout((function() { return function() { doTest(test); }})(), 0);
}
}
JSFiddle: http://jsfiddle.net/E3zvL/4/

Categories