I've encountered a very badly designed website, and most of the "dynamic" content on the site is changed within setTimeout/setInterval functions.
There is one very annoying setInterval function which checks page activity very quickly, and I would like to override this function.
What I tried is clearing all the setInterval values, one by one to check if the function stopped. Also, clearing all the possible setInterval values like this: for(let i = 0; i < 1000; i++) clearInterval(i);, stops the "dynamic" page rendering, WHICH I DONT WANT TO
Question: 1. is there any way to look into the interval or timeout function and clear them?
2. is there a better way?
My current solution: I'm overriding the setInterval and setTimeout before page loaded, and log the function .toString() within.
The short answer is no, you cannot determine anything about the setTimeout/setInterval callback given a timerId. It sounds as if you don't have access to edit the underlying Javascript to prevent this action. If you can get your JS to load before the code in the page, then what you can do is replace setInterval or setTimeout with your own code, where you can increase the interval to whatever you want. For example:
let setTimeoutOld = setTimeout;
setTimeout = (cb, interval) => {
if (interval < 1000) {
interval = 1000;
}
setTimeoutOld(cb, interval);
}
Now if the page does something like:
setTimeout(() => { console.log('fired') }, 1);
The timeout won't fire until at least 1000ms have passed. If you only wanted to modify a specific setTimeout based on the contents of the cb, you could do what you mentioned in your work-around: calling .toString() on the function and comparing it to some previously generated .toString() (partial or complete) and then doing whatever you wanted.
I assume you have access to code wherever it's setting timeout or interval.
So just take a global array and push it's output to it. Then iterate that array to clear everything.
For ex.
timeouts = [];
now, in code where there's timeout like
var timeout = setTimeout(<callback> , <interval> ); // push it's output to that global.
timeouts.push(timeout);
Then at the very end clear that.
for(time of timeouts) {
clearTimeout(time);
}
Similarly, for Interval.
Hope this is what you are looking for.
Related
I want to fade in different elements of a page one by one with jQuery fadeIn function. It's working but the delay between two fadeIn are not consistent. Randomly some elements appear sooner than the others. What am I doing wrong? I am using the following code to achieve that.
setInterval(function(){
$('.showTime .appr').each(function(index){
$(this).delay(500*index).fadeIn(400);
});
}, 50);
Note: The setInterval function is used because I am waiting for the class 'showTime' to be added to the body tag, by some other function.
By using setInterval() you are causing this code to be called every 50ms, even after the .showTime class has been added which is causing the strange behavior you are seeing. If you assign the result of setInterval() to a variable you can then use clearInterval() on it once the class has been added, and your selector returns DOM elements:
// track the interval so we can clear it
var myInterval;
myInterval = setInterval(function(){
// try to match elements with the selector
var elements = $('.showTime .appr');
// if the length is non-zero...
if ( elements.length ){
// clear the interval
clearInterval(myInterval);
// run your code
$('.showTime .appr').each(function(index){
$(this).delay(500*index).fadeIn(400);
});
}
}, 50);
All that said, this is probably not the best design pattern - it would be better to use a callback rather than polling and eating up CPU.
I am working on a project in which I am dynamically generating many setInterval's, and so it is not possible to store their reference in a variable so that it could be used to clearInterval.
Just wanted to ask you guys if anyone has an idea of how to clearInterval on a particular div with an Id.
In my project, when setInterval is supposed to be cleared, I am also removing the element from document body. So when setInterval is called again, I can put a condition to check if the element with that particular id exists and only then I can execute the setInterval code.
Like this,
if(document.getElementById("char0") != null)
{
// execute the setInterval code.
}
But this approach will still take CPU time. I am dynamically generating around 150 setIntervals, not possible to create variable reference for them. Please help if you have any clue of how this could be achieved.
Try to store the interval variable in a closure:
var createInterval = function(elementId){
var interval;
interval = setInterval(function(){
if(document.getElementById(elementId) == null){
clearInterval(interval);
}else{
//Your code
}
},1000);
};
So you can create any number of intervals what you like and remove it when those DOM elements are gone.
createInterval('element1');
createInterval('element2');
createInterval('element3');
But as what #alexander-omara said, use only few interval to update all elements is better solution in term of CPU usage.
You can easily keep a reference to a interval ID on a DOM element:
var element = document.getElementById("char0");
element._someInterval = setInterval(function(){
//Some code.
}, 1000);
And then clear it using:
if(element._someInterval)
{
clearInterval(element._someInterval);
}
However, creating hundreds of intervals does not sound like a very efficient means of doing anything. You way want to create 1 interval, and loop over an array of elements.
You need to have interval variable to call clearinterval() properly.
If you create variables dynamically like "interval+divid" so each time you get Id, create variable name by this convention and clear the same.
I am trying to load a random image at a random time. For some reason this is not randomizing the time, though it does randomize the image. Any ideas what's wrong?
var randomTime2 = 3000; //initialize the random time with this value to start
setInterval(function(){
var randomNum = Math.floor((Math.random()*3)+1);//random num for image
$('.recent-project2 img').fadeTo('slow',0,function(){
var randomImg = "img/recent-projects-"+randomNum+".jpg";
$('.recent-project2 img').attr('src',randomImg);
$('.recent-project2 img').fadeTo('slow',1);
});
randomTime2 = Math.floor(Math.random()*10000);//reset random time
return randomTime2; //return random time
},randomTime2);
Use setTimeout and re-trigger at the end of the function with a random time.
The setInterval call will just add your function and the required interval to an internal table to remember to call your code when the expected delay period passed. Note however that even if you change the variable used to specify the interval this will have no effect on the internal table: that value has been read when you called setInterval and it's now stored.
To randomize the callback time give your function a name and just use setTimeout instead of setInterval:
function MyCallback() {
...
setTimeout(myCallback, new_delay);
}
setTimeout(myCallback, first_delay);
with this approach at each call you can decide a different delay before next call.
You can't change the value of randomTime2 inside the function as it's pass by value, not reference.
setInterval(someFunction, someNumberValue)
This line of code will call someFunction every someNumberValue-miliseconds. The value is not updated dynamically.
There's lots of ways you could make this work, but I suggest simply using setTimeout and making the end of someFunction call it again. For instance:
//psudo-code, might not actually run, just showing you the general idea.
var someFunction = function(){
console.log("Whatever.");
}
var repeatFunction = function(){
someFunction()
var timeoutID = window.setTimeout(repeatFunction, Math.random()*10000);
}
repeatFunction(); //Starts the loop.
Someone know if after I displays an HTML page I can access a specific ID (getElementById), and change it a value several times?
I want to present a client-side some string and change it several times according the progress of the program, but I can not, it writes to me only recently.
For example:
<script type="text/javascript">
function foo(){
for(var i = 0; i<10000; i++){
document.getElementById('myTag').innerHTML = i;
}
}
</script>
In this case, I do not see the numbers run. I see only the last one.
If I put alert inside the loop - the value is changed.
As i understand your question you want a countup from 0 to 10000 ?
and you want to see the progression on screen ? you could do something like that :
http://jsfiddle.net/camus/ayJFM/
var interval = 500;//milliseconds
var foo = (function () {
var i = 0;
var func = function () {
if (i < 10000) {
document.getElementById("myTag").innerHTML = i;
i += 1;
setTimeout(func, interval);
}
};
return func;
})();
setTimeout(foo, interval);
You're almost there. The only thing you're doing wrong is replacing the innerHTML content instead of adding to it. Change this:
document.getElementById('myTag').innerHTML = i;
to this:
document.getElementById('myTag').innerHTML += i;
Additional/alternative answer:
Wait. I've just reread your question and realized that there is another way of interpreting it. The way you ask it is quite vague so I'm leaving the above answer as is.
The reason you don't see "running numbers" as you process the for loop is because you misunderstand how javascript works in the browser.
The browser's event loop runs something like this:
1. Fetch content
2. Run javscript
3. Render content
then repeat forever
This is how javascript works. So running a simple for loop like you're doing. The browser executes the script until there is nothing else to execute (step 2). Once javascript have finished executing then it will start the render process (step 3). Obviously, by this time the value of i is the final value and therefore you only see the final value.
The browser never interrupts running javascript to render/update the page. So, how do people implement countdown timers etc? They do it by scheduling a piece of javascript to execute in the next iteration of the event loop. That is to say, the let the browser enter step 3 and at the appropriate moment as the browser enters step 2 again they run the script they want.
Javascript basically provides two ways to do this: setTimeout and setInterval.
How setTimeout works is this:
step 1. nothing to do
step 2. setTimeout schedules a piece of javascript to run at a later time
Note that the javascript does not execute yet until setTimeout
expires.
step 3. let the browser update the page
many, many loops of steps 1-3
step 2 (some time later).
setTimeout expires and the piece of javascript executes
step 3. let the browser update the page
So, the get the effect you want, you need to do it like this:
function foo(){
var i = 0;
var update = function(){
document.getElementById('myTag').innerHTML = i;
i++;
if (i<10000) {
setTimeout(update,100);
}
};
update();
}
I am using Selenium to test a web app that uses Dojo, and it uses java script to display certain elements. I want to wait until all of the elements are desplayed before I try to manipulate the page, however I am having trouble.
I have started by waiting for the dojo inFlight variable to be 0, this says that all ajax has finished. This doesn't always work because it seems to do some things on a timeout afterwards.
I have also tried repeatedly looking for the element, but this isn't too nice, as perhaps there is some javascript later which will use this field in some way.
So basically I want a method (in firefox at least) to query the javascript waiting to run on a setTimeout (or setInterval) I could even cope with a way of wrapping the built in call through a function of my own just to keep track of this.
Any thoughts or suggestions appreciated!
Every function in JavaScript can be replaced. Consider something like this:
window.originalSetTimeout = window.setTimeout;
window.setTimeout = function(func, delay, params) {
window.timeoutCounter++;
window.originalSetTimeout(window.timeoutCallback, delay, [func, params]);
}
window.timeoutCallback = function(funcAndParams) {
window.timeoutCounter--;
func = funcAndParams[0];
params = funcAndParams[1];
func(params);
}
Then:
selenium.waitForCondition("window.timeoutCounter == 0");
Whenever you call setTimeout of setInterval -- a timer id is returned.
Save that timer id in an array
Inside the function that you're calling on the timeout, pop that timer id off the array. Because we have to remove that id from the array as soon as the timer ends.
Any time you want to check the no. of active timers, just query the length of that array.
Another approach could be like this
const timeoutIndexThen = setTimeout(() => {});
// Some code that might call timeouts...
const timeoutIndexNow = setTimeout(() => {});
const countOfTimeoutsFiredSinceThen = timeoutIndexNow - timeoutIndexThen - 1;
It is based on the fact that each timeout will return a number that is greater by 1 on each call.
So we create some dummy timeout just to get this number at some point.
Then, after a while we call it again and we get a new number. Difference between those numbers is how many times interval was called in between.
Downside of this is that you have to actually create the timeout. Upside is that you don't have to modify original function.