setTimeout doesnt fire after first iteration in Internet Explorer - javascript

I have an event that I'm firing every 5 seconds to check if a file has finished processing.
I'm doing the following:
if (InSuppArray(item.Id) == false && item.Status() == "Queue") {
var t = setTimeout(function () { checkQueuedSupp(item.OrderId) }, 5000);
suppIds.push({ Id: item.OrderId, TimerId: t });
}
Basically, multiple files can be uploaded so this created an array of timers and kills them as the files completes.
This works great in Firefox and Chrome, but the timer only fires one time in Internet Explorer.
Is there a better way to do this? I searched around and found some issues with IE and setTimeout but most of those were alluding to the fact that it just never works in IE, which mine at least fires once.

1) Is is working for first iteration? Yes your code works fine.
2) If repetitive is your problem then check the following:
setTimeout is not a repetitive method. Instead use setInterval.
if (InSuppArray(item.Id) == false && item.Status() == "Queue") {
var t = setInterval(function () { checkQueuedSupp(item.OrderId) }, 5000);
suppIds.push({ Id: item.OrderId, TimerId: t });
}
To make setTimeout as repetitive, try to make it has recursive.

setTimeout is to delay execute the function, not repeatedly to execute it. What you want is setInterval which will execute your function for every time interval you specified.

Related

setTimeout blocking issue

I'm writing a "Game of Life" in javascript. I have all the logic done in a function called doGeneration(). I can repeatedly call this from the console and everything goes as planned, however, if I put it in a while loop the execution blocks the UI and I just see the end result (eventually).
while (existence) {
doGeneration();
}
If I add a setTimeout(), even with a generation limit of say 15, the browser actually crashes (Canary, Chrome).
while (existence) {
setTimeout(function() {
doGeneration();
},100);
}
How can I call doGeneration() once every second or so without blocking the DOM/UI?
You want setInterval
var intervalId = setInterval(function() {
doGeneration();
}, 1000);
// call this to stop it
clearInterval(intervalId);
I would use requestAnimationFrame(doGeneration). The idea of this function is to let the browser decide at what interval the game logic or animation is executed. This comes with potential benefits.
https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/
Rather than using setINterval or setTimeout and assume some random time interval will be enough for the UI to update you shoul/could make the doGeneration smart enough to call itself after dom was updated and if the condition of existence is satisfied.

How do I slow down the execution of a jquery click function?

I use a simple jquery command in the Google Chrome console to manage my site. Basically, I have to approve a number of new requests every day, so I use:
$('.approve').click();
where 'approve' is the class name of the button that needs to get clicked. This saves me hours. However, this crashes my browser every time, and sometimes doesn't work, mainly because of the resource taxing it put on my laptop. I was looking for a way to slow down the actions of the function. I tried...
$('.approve').click().delay(1000);
to try and slow it down by 1 second between button clicks. This didn't seem to work (it ran without errors but I don't think it slowed down the clicking.
Any ideas?
Edit:
Someone pointed out that this may be a duplicate of another question. The reason it isn't is that the other top answer focuses on using JS to define a function that uses setTimeout(), where I am looking for a native jquery method of doing it. I understand jquery is written in JS, but because I'm using it in a command console, I don't have the luxury of multiple lines of coding space.
Can anyone also tell me why the above function wouldn't work? It seems like it should, based on my research.
Thank you in advance.
Wait 1 second between each click:
You will need to iterate over each .approve-button, then trigger the click event for each button with a second in between: (setTimeout)
$('.approve').each(function(index) {
var $approve = $(this);
setTimeout(function() {
// Simulation click event
$approve.trigger('click');
// 0, 1, 2, 3, ... times 1000 to bring delay to miliseconds
}, index * 1000);
});
One liner (For IE9+):
$(".approve").each(function(c){setTimeout(function(c){c.click()},1e3*c,$(this))});
One liner:
$(".approve").each(function(e){var i=$(this);setTimeout(function(){i.click()},1e3*e)});
You can add a delay on the function click like so
$(".approve").click(function(){
setTimeout(function(){
// Do something
}, 1000);
});
If you want to exectue your function once, use setTimeout()
$(".approve").click(function(){
setTimeout(function(){
}, 1000);
});
If you want to exectue it every second, use setInterval()
when click you have to run a function that will execute setTimeout function
$('.approve').click(function(){
setTimeout(function(){
// here some code u want to execute after 5 sec //
}, 5000);
});

cordova setTimeout function

I'm encountering a problem with setTimeout, and I can't figure out why.
I'm using cordova, and the setTimeout function leads to curious comportment.
app.displayData = function(device) {
app.readThermometer(device);
app.readAccelerometer(device);
app.readHumidity(device);
app.readMagnetometer(device);
//setTimeout(app.displayData(device), 5000);
};
This is executed once.
app.displayData = function(device) {
app.readThermometer(device);
app.readAccelerometer(device);
app.readHumidity(device);
app.readMagnetometer(device);
setTimeout(app.displayData(device), 5000);
};
This is executed many times, but way faster than once every 5 seconds. It is a problem for me because it prevent jQuery from executing correctly. (Never getting the dom modification expected)
What am I missing? If it is a bug in cordova, do you know other way to delay code execution in javascript?
You're calling the function app.displayData directly
setTimeout(app.displayData(device), 5000);
Try the following instead
setTimeout(function () {
app.displayData(device);
}, 5000);
And another alternative if you prefer Function.bind
setTimeout(app.displayData.bind(app, device), 5000);

clearInterval - something's amiss

It seems that everyone has a few problems with clearInterval. I have built a slider that allows people to hover a click on arrows. The banner also rotates ever few seconds. I want to be able to have the auto-rotate turn off after someone clicks on one of the arrows.
Here's my code:
$(function(){
var intvl = 0;
intvl = setInterval(heroTransitionNext, 2000);
$('.rightArrow').click(function(){
window.clearInterval(intvl);
});
});
EDIT:
Here is the function it is calling:
function heroTransitionNext() {
$('.HP-hero li').filter(':visible').fadeOut('normal', function () {
if ($(this).next().length != 0) {
activeZone = parseInt(activeZone) + 1;
$(this).next().fadeIn('normal', heroNavHighlight(activeZone));
} else {
activeZone = 1;
$('.HP-hero li:first-child').fadeIn('normal', heroNavHighlight(activeZone));
}
$(this).hide();
});
};
To stop the animation you can use jquery's .stop() but not sure whether it'll solve the problem or not that you are facing (didn't visualize) but you can give it a try
$('.HP-hero li').stop(1,1); // or try $('.HP-hero li').stop()
window.clearInterval(intvl);
As say2joe said that clearInterval will just stop the function from invoking next time but it won't clear the current queue (he is right) so in that case stop could be used.
About Stop.
Depending on how much work your heroTransitionNext function is doing, it may still be executing even though the interval is cleared -- in other words, clearing the interval will stop the function from being invoked -- but, any instance of the function(s) executing in memory will continue to execute until finished.
To be more clear, here's a use case (you can check this out yourself by using a profiler in Firebug or Developer Tools):
heroTransitionNext execution time is 2.1 seconds.
clearInterval is invoked 6.1 seconds after setInterval is invoked.
At 6.1 seconds, heroTransitionNext has been invoked four times. The first three executions have completed, however, the fourth will not complete until it finishes executing (at 8.1 seconds since setInterval was called). Note: In this use case, each successive invokation will execute while the last invokation's execution is still continuing (for 100 more ms) -- in other words, you'll have execution overlap from 2 to 2.1, 4 to 4.1, and 6 to 6.1 second intervals.
If the function takes longer to execute than the interval set, use a recursive function with setTimeout(). The following link will give you a good example.
Also, a good reference for explanation is https://developer.mozilla.org/en/DOM/window.setInterval.

When using setInterval, if I switch tabs in Chrome and go back, the slider goes crazy catching up

I have a jQuery slider on my site and the code going to the next slide is in a function called nextImage. I used setInterval to run my function on a timer, and it does exactly what I want: it runs my slides on a timer. BUT, if I go to the site in Chrome, switch to another tab and return, the slider runs through the slides continuously until it 'catches up'. Does anyone know of a way to fix this. The following is my code.
setInterval(function() {
nextImage();
}, 8000);
How to detect when a tab is focused or not in Chrome with Javascript?
window.addEventListener('focus', function() {
document.title = 'focused';
},false);
window.addEventListener('blur', function() {
document.title = 'not focused';
},false);
To apply to your situation:
var autopager;
function startAutopager() {
autopager = window.setInterval(nextImage, 8000);
}
function stopAutopager() {
window.clearInterval(autopager);
}
window.addEventListener('focus', startAutopager);
window.addEventListener('blur', stopAutopager);
Note that in the latest version of Chromium, there is either a bug or a 'feature' which is making this less reliable, requiring that the user has clicked at least once anywhere in the window. See linked question above for details.
I post an answer here: How can I make setInterval also work when a tab is inactive in Chrome?
Just do this:
setInterval(function() {
$("#your-image-container").stop(true,true);
nextImage();
}, 1000);
inactive browser tabs buffer some of the setInterval or setTimeout functions.
stop(true,true) - will stop all buffered events and execute immadietly only last animation.
The window.setTimeout() method now clamps to send no more than one timeout per second in inactive tabs. In addition, it now clamps nested timeouts to the smallest value allowed by the HTML5 specification: 4 ms (instead of the 10 ms it used to clamp to).
A few ideas comes to mind:
Idea #1
You can make it so that a short burst is idempotent. For example, you could say:
function now() {
return (new Date()).getTime();
}
var autopagerInterval = 8000;
function startAutopager() {
var startImage = getCurrentImageNumber();
var startTime = now();
var autopager = setInterval(
function() {
var timeSinceStart = now() - startTime();
var targetImage = getCurrentImageNumber + Math.ceil(timeSinceStart/autopagerInterval);
if (getCurrentImageNumber() != targetImage)
setImageNumber(targetImage); // trigger animation, etc.
},
autopagerInterval
);
return autopager;
}
This way even if the function runs 1000 times, it will still run in only a few milliseconds and animate only once.
note: If the user leaves the page and comes back, it will have scrolled. This is probably not what the original poster wants, but I leave this solution up since it is sometimes what you want.
Idea #2
Another way to add idempotence (while still keeping your nextImage() function and not having it scroll to the bottom of the page) would be to have the function set a mutex lock which disappears after a second (cleared by another timeout). Thus even if the setInterval function was called 1000 times, only the first instance would run and the others would do nothing.
var locked = false;
var autopager = window.setInterval(function(){
if (!locked) {
locked = true;
window.setTimeout(function(){
locked=false;
}, 1000);
nextImage();
}
}, 8000);
edit: this may not work, see below
Idea #3
I tried the following test:
function f() {
console.log((new Date()) + window.focus());
window.setTimeout(f, 1000);
}
f();
It seems to indicate that the function is being called every second. This is odd... but I think this means that the callbacks are being called, but that the page renderer refuses to update the page in any graphical way while the tab is unfocused, delaying all operations until the user returns, but operations keep piling up.
Also the window.focus() function doesn't say if the window has focus; it GIVES focus to the window, and is thus irrelevant.
What we want is probably this: How to detect when a tab is focused or not in Chrome with Javascript? -- you can unset your interval when the window loses focus (blur), and reset it when it gains focus.
I don't know exactly what is going on in your function nextImage(), but I had a similar issue. I was using animate() with setInterval() on a jQuery image slider that I created, and I was experiencing the same thing as you when I switched to a different tab and back again. In my case the animate() function was being queued, so once the window regained focus the slider would go crazy. To fix this I just stopped the animate() function from queuing.
There are a couple ways you can do this. the easiest is with .stop(), but this issue and ways to fix it are documented in the jQuery docs. Check this page near the bottom under the heading additional notes: http://api.jquery.com/animate/
I had faced similar issue, somehow this code below works fine for me.
var t1= window.setInterval('autoScroll()', 8000);
window.addEventListener('focus', function() {
focused = true;
window.clearInterval(t1);
t1 = window.setInterval('autoScroll()', 8000);
},false);
window.addEventListener('blur', function() {
focused = false;
window.clearInterval(t1);
},false)
function autoScroll()
{
if ( running == true){
if ( focused = true){
forwardSlide();
}
}
else {
running = true;
}
}
If you are using Soh Tanaka's image slider then just add this...to solve your Google Chrome issue:
$(".image_reel").stop(true, true).fadeOut(300).animate({ left: -image_reelPosition}, 500 ).fadeIn(300);
Take note of the .stop() function. Ignore the fading in and out stuff, that's what I used on my version
Thanks
Seconding the comment by jgerstle to use page visibility events instead, see https://www.w3.org/TR/page-visibility/#example-1-visibility-aware-video-playback for more around subscribing to 'visibilitychange' for hidden/visible states.
This seems to be more useful than focus/blur these days as it covers visible-but-not-selected windows if concerned also about multi-window operating systems.

Categories

Resources