Timeout in Jquery to update the Dom? - javascript

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/

Related

jquery setTimeout too much recursion

I have read from multiple places that setTimeout() is preferable to setInterval() when setting something up to basically run forever. The code below works fine but after about an hour of running Firefox (38.0.1) throws an error of too much recursion.
Essentially I have it grabbing a very small amount of text from counts.php and updating a table with that information. The whole call and return takes about 50ms according to the inspectors. I'm trying to have it do this every x seconds as directed by t.
I suspect if I switch to setInterval() this would probably work, but I wasn't sure what the current state of the setTimeout() vs setInterval() mindset is as everything I've been finding is about 3-5 years old.
$(document).ready(function() {
t = 3000;
$.ajaxSetup({cache: false});
function countsTimer(t) {
setTimeout(function () {
$.getJSON("counts.php", function (r) {
$(".count").each(function(i,v) {
if ($(this).html() != r[i]) {
$(this).fadeOut(function () {
$(this)
.css("color", ($(this).html() < r[i]) ? "green" : "red")
.html(r[i])
.fadeIn()
.animate({color: '#585858'}, 10000);
})
};
});
t = $(".selected").html().slice(0,-1) * ($(".selected").html().slice(-1) == "s" ? 1000 : 60000);
countsTimer(t);
});
}, t);
};
countsTimer(t);
});
Update: This issue was resolved by adding the .stop(true, true) before the .fadeOut() animation. This issue only occurred in Firefox as testing in other browsers didn't cause any issues. I have marked the answer as correct in spite of it not being the solution in this particular case but rather it offers a good explanation in a more general sense.
You should indeed switch to setInterval() in this case. The problem with setInterval() is that you either have to keep a reference if you ever want to clear the timeout and in case the operation (possibly) takes longer to perform than the timeout itself the operation could be running twice.
For example if you have a function running every 1s using setInterval, however the function itself takes 2s to complete due to a slow XHR request, that function will be running twice at the same time at some point. This is often undesirable. By using setTimout and calling that at the end of the original function the function never overlaps and the timeout you set is always the time between two function calls.
However, in your case you have a long-running application it seems, because your function runs every 3 seconds, the function call stack will increase by one every three seconds. This cannot be avoided unless you break this recursion loop. For example, you could only do the request when receiving a browser event like click on the document and checking for the time.
(function()
{
var lastCheck = Date.now(), alreadyRunning = false;
document.addEventListener
(
"click",
function()
{
if(!alreadyRunning && Date.now() - lastCheck > 3000)
{
alreadyRunning = true;
/* Do your request here! */
//Code below should run after your request has finished
lastCheck = Date.now();
alreadyRunning = false;
}
}
)
}());
This doesn't have the drawback setInterval does, because you always check if the code is already running, however the check only runs when receiving a browser event. (Which is normally not a problem.) And this method causes a lot more boilerplate.
So if you're sure the XHR request won't take longer than 3s to complete, just use setInterval().
Edit: Answer above is wrong in some aspects
As pointed out in the comments, setTimeout() does indeed not increase the call stack size, since it returns before the function in the timeout is called. Also the function in the question does not contain any specific recursion. I'll keep this answer because part of the question are about setTimeout() vs setInterval(). However, the problem causing the recursion error will probably be in some other piece of code since there is not function calling itself, directly or indirectly, anywhere in the sample code.

How to submit a request for some given condition using jscript and jquery?

I have tried this code:
while (true) {
$(document).ready(function() {
setInterval(function () {
if ($("h2").text() == "Qu’est-ce qu’une année-lumière ?") {
$("#choice2").delay(200).queue(function () {
$(this).click().dequeue()
})
}
}, 10000)
}
. My aim is actually to send an answer as the page DOM is already ready if the element in the tag is verified, then i want to repeat this for as i am on that page. I tried many codes but my browser doesn't like them: it freezes... that is why i try to use an interval, but i am unable to control it yet. please i need your help...
The browser freezes because you have an infinite loop. It will just keep binding more and more ready events until the code is stopped for taking too long to run, or when the browser crashes because you have bound a zillion event handlers.
Adding the interval was the right move to make the code run more than once, but the while loop still kept it from working.
Remove the while loop, and your code will run. You don't need to dequeue a function that you queued, it will be dequeued when it runs.
$(document).ready(function() {
setInterval(function () {
if ($("h2").text() == "Qu’est-ce qu’une année-lumière ?") {
$("#choice2").delay(200).queue(function () {
$(this).click();
});
}
}, 10000);
}
The interval runs the code every 10 seconds, so there doesn't seem to be any reason to wait for 200 ms before invoking the click, though.

setTimeout inside while loop

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);

jQuery while object.hasClass

I'm trying to find a way to stop a function at a certain point until something does not have a specific class anymore. I cannot change the place where this class is being assigned and removed because it's a plugin.
I was thinking of doing something like this
function DoSomething() {
while ($('div.divControl').hasClass('playing'))
{
//Wait here
}
};
Is this the correct way to go?
This will block so the element will never be changed, as no other code will execute.
What you need to use is an interval:
var interval = setInterval(DoSomething, 500);
function DoSomething() {
if ($('div.divControl').hasClass('playing'))
{
// Do something
clearInterval(interval);
}
};
This will execute the function every half second. The interval will be cancelled after the function succeeds.
No, that will just hang the browser as it goes into an infinite loop.
Your best bet (as best I can think at the moment anyhow) is to do a setTimeout on the function and have it check to see if it your div still has the class every quarter of a second or so.
Still, not nice at all =[

jQuery execute code each time element has class

I'm trying to execute a piece of code each time a specific element has a certain class in jQuery.
The problem I'm experiencing is that the code only executes once, then seems unactive. I'm using an if statement, but I also tried while. When I tried while the nothing really worked so that wasn't a good idea. Is there any solution? Here's the code:
if($(".slide:first").hasClass("active-slide")) {
$(".prev").hide();
$(".next").click (function () {
$(".prev").show();
});
}
JQuery queries are performed only once. You could execute it in an interval:
var checkPage = function(){
if($(".slide:first").hasClass("active-slide")) {
$(".prev").hide();
$(".next").click (function () {
$(".prev").show();
});
}
}
var intrvl = setInterval( checkPage, 300 );
This might work, but it could become really slow on big pages.
I'd rather attach the checkPage() function to the slide change event.
Wrap it in a each(), so that it executes every time slider:first occurs.
$(".slide:first-child").each(function(){
// your function goes here
});
EDIT: :first only targets the first instance of it on the page, so it will only fire one time anyway. You are probably looking for :first-child.

Categories