How do I make this javascript async while loop work? - javascript

I'm attempting to get a google gpt tag to refresh a maximum number of times if, when loaded, it comes back empty.
<script type="text/javascript">
googletag.cmd.push(function() {
var slot1 = googletag.defineSlot("/gtpConfigStuff",[300,600],"gtpConfigStuff")
.addService(googletag.pubads())
.setTargeting("pos", "BTF")
.setTargeting("URL", encodeURIComponent(window.location));
googletag.enableServices();
googletag.display("gtpConfigStuff");
googletag.pubads().addEventListener('slotRenderEnded', function(event) {
var tries = 0;
while (tries<=2 && event.isEmpty==true) {
//googletag.pubads().refresh([slot1]);
//setTimeout(function() {
tries++;
console.log(tries);
//}, 1000);
}
console.log("done");
});
});
</script>
With the above lines commented out it works as it should.
With the refresh function call it will loop indefinitely.
The setTimeout I thought might allow the refresh to finish.
Thanks.

Your script will load indefinitely because you're resetting your tries variable indefinitely
var tries = 0; // Set your variable here...
googletag.pubads().addEventListener('slotRenderEnded', function(event) {
// ...and not here. Otherwise it will always reset to 0 when the event triggers.
// "tries" will still be available in here though as a closure so you can still use it
if (tries<=2 && event.isEmpty==true) {
googletag.pubads().refresh([slot1]);
tries++;
}
});

Related

JavaScript - getElementById doesn't work on specific page

I want to automate clicking the agree button to Google's cookie policies.
(I clean cookies after closing a tab, and I don't want to create a google account, so I get asked every time I use google)
There is a div element with the ID "introAgreeButton" that I'm trying to access with my script:
<div role="button" id="introAgreeButton" [...]></div>
However, document.getElementById('introAgreeButton') always returns null.
My first thought was that the element wasn't loaded by the time my function was executed. But it doesn't work if I execute it on window.onload, or even if I run it in a loop until the element is definitely there:
window.onload = function() {
var x = document.getElementById('introAgreeButton')
console.log(x)
}
Output:
null
function loop() {
var x = document.getElementById('introAgreeButton')
if (x) {
console.log('success')
} else {
loop()
}
}
Output:
null
null
null
...
Can be tested on https://www.google.com/search?hl=en&q=test
Anyone have an idea why this is and how to solve it?
Edit: I execute the script via the browser extension TamperMonkey
You can use setInterval to check if element is rendered in DOM like this :
document.addEventListener('DOMContentLoaded', function () {
var intervalID = null;
function checkElementInDOM () {
var element = document.getElementById('introAgreeButton');
if (element) {
clearInterval(intervalID);
// DO YOUR STUFF HERE ...
}
}
intervalID = setInterval(checkElementInDOM, 100);
});
To be used intelligently, however, so as not to have a setInterval which works continuously. Maybe think about adding a maximum number of attempts.

clearInterval not working in javascript chrome extension

I'm trying to make a chrome extension and in my content script which runs only on www.youtube.com it's supposed to check, document.getElementById("movie_player"), if a particular div element has loaded or not. If not setInterval and wait a second. If it has loaded then run alert("Hello") and clearInterval which will end the script.
However, it's not working. Even after I find the element, and it says "Hello" it continues to say hello which means setInterval is still calling my function after 1000 milliseconds even though it should have been cleared.
Here's my content.js file:
var timeOut;
function CheckDOMChange()
{
moviePlayer = document.getElementById("movie_player");
if(moviePlayer !== null)
{
WhenVideoLoads();
}
timeOut = setInterval("CheckDOMChange();", 1000);
}
function WhenVideoLoads()
{
alert("Hello");
clearInterval(timeOut);
}
CheckDOMChange();
As you can see, I made timeOut a global variable so it shouldn't be a scope problem. So I really don't know what the problem is because the condition is being met and clearInterval is being called.
Any help would be much appreciated.
The issue is that you have setInterval inside the function. Basically, for every call you are setting interval which creates multiple setIntervals. Remove the setInterval from within the function
var timeOut;
function CheckDOMChange() {
moviePlayer = document.getElementById("movie_player");
if (moviePlayer !== null) {
WhenVideoLoads();
}
}
function WhenVideoLoads() {
alert("Hello");
clearInterval(timeOut);
}
timeOut = setInterval("CheckDOMChange();", 1000);
By calling CheckDOMChange recursively, you are actually exponentially creating timers, and you are only clearing the last timer when calling WhenVideoLoads.
You may try to run this snippet and inspect the console to see what is happening, and see that clicking the button will clear the last timer but not all those that have been created before.
var timeOut;
var counter = 0;
function CheckDOMChange()
{
console.log("counter :", counter);
if (counter > 16) {
console.log("Stop creating new timers!");
return;
}
timeOut = setInterval("CheckDOMChange();", 5000);
console.log("timeOut :", timeOut);
counter ++;
}
function WhenVideoLoads()
{
console.log("Clearing ", timeOut);
clearInterval(timeOut);
}
CheckDOMChange();
<button onclick="WhenVideoLoads()" id="clear">Clear timer</button>
You should avoid calling CheckDOMChange recursively, and proceed as #cdoshi suggested.
Hope this helps!

Javascript While or If statement to run a set interval function with

I need a javascript while look that looks for the condition ":visible" on a DOM object and only runs the code when the DOM object is actually visible.
This is my code so far.
if (("#rightPanel").is(":visible") == true){
// It's visible, run fetch on interval!
setInterval(function() {
updateChatField()
}, 500);
} else {
// Do Nothing!
};
What do I need to adjust to get my desired effect? Right now I'm getting ("#rightPanel").is is not a function.
You forgot the $ sign:
if ($("#rightPanel").is(":visible") == true){
// It's visible, run fetch on interval!
setInterval(function() {
updateChatField()
}, 500);
} else {
// Do Nothing!
};
Actually, if I understood correctly, you need the interval to be constantly running so it detects when the element changes to visible. I'd suggest something like:
var $rightPanel; // cache the element
function checker() {
if ($rightPanel.is(":visible"))
updateChatField();
}
function init() {
$rightPanel = $("rightPanel"); // cache
window.setInterval(checker, 500);
}
Then to start it, just call init() after the page has loaded.

clearInterval function not clearing setInterval function

I utilized this resource to structure my code: http://www.w3schools.com/jsref/met_win_clearinterval.asp
var intervalID = setInterval(function(){ ogpeWrapper() }, 10);
function ogpeWrapper() {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
}(jQuery);
function myStopFunction() {
if (document.getElementById('colWrapperContainer')) {
clearInterval(intervalID);
setIntervalID = undefined;
}
}
My ogpeWrapper function is running, but the clearInterval function is not.
Basically, once $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll(''); runs, I want the interval to stop running it.
Edit - 12:24pm CST:
This is the base code I utilize to wrap the listed elements -
(function($) {
$("#breadcrumbAds, #breadcrumbWrapper, #containerTopParsys, #leftColWrapper, #rightColWrapper").wrapAll('<div id="colWrapperContainer"></div>');
})(jQuery);
This code works, but it doesn't process the change until after the DOM has completely loaded. I need the function to work as soon as those elementals are all available. So I need to use a setInterval to process the function, then clear the interval once the function is processed.
If anyone knows of another way to do this, besides a setIterval, please let me know.
You need to create a definite if else condition within the variable so you know exactly when it will start and when it will stop. Also, because the minimum millisecond interval timing is not consistent across browsers, although you want it to detect really fast, I would recommend a "safer" number and use 100 as the minimum instead. The .length method is a handy little way for you to check if an element is on a page; You can use it as a pseudo dynamic true/false conditional. Lastly, in your .wrapAll() tag, I swapped your single and double quotes, as it is best practice to do such.
var colWrapper = setInterval(function(){
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
$("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper").wrapAll("<div id='colWrapperContainer'></div>");
}
}, 100);
Here is a working example for your reference Wrap Example
Update:
Example for putting the script inside the <body> tag (no window.load/document.ready) so that it runs independently as soon as it is loaded.
<script type="text/javascript">//<![CDATA[
//http://stackoverflow.com/questions/33483000/clearinterval-function-not-clearing-setinterval-function/33483267#33483267
//Auto Wrap Solution
//Alexander Dixon [11-02-2015]
var wrapThese = $("#breadcrumbWrapper, #leftColWrapper, #rightColWrapper");
var colWrapper = setInterval(function () {
if ($('div#colWrapperContainer').length > 0) {
var doNothing = "";
clearInterval(colWrapper);
} else {
wrapThese.wrapAll('<div id="colWrapperContainer"></div>').addClass('success');
}
}, 100);
//]]>
</script>

Javascript - Refresh - Memory Leak

I am seeing a major memory leak within Firefox and IE on my below code. To be fair, it could very well be my poor implementation and it needs changing, to allow Firefox and other browsers to garbage collect.
Does anyone have any suggestions on how to tweak the code to allow for a more efficient way of refreshing the page?
<input type="checkbox" onclick="sel1()" id="AutoRefresh">
<script type="text/javascript">
function sel1(){
var ref = document.getElementById('AutoRefresh').checked;
if(ref == true) {
setInterval(function(){
document.getElementById('dataRefreshButton').click(); }, 2000);
}
window.alert("Auto refresh on");
}
</script>
I think this will be better.
<script type="text/javascript">
function getdata(){
// get your data
}
var intGetData;
function sel1(){
var ref = document.getElementById('AutoRefresh').checked;
if(ref == true) {
intGetData = setInterval(getdata, 2000);
window.alert("Auto refresh on");
}
else{
clearInterval(intGetData);
window.alert("Auto refresh off");
}
}
</script>
Change setInterval to setTimeout. Your current code will set up a new interval to click the element every 2s when clicked. If you click once, you trigger an avalanche.
Or even better, you stop the interval:
var handle = null;
function sel1(){
var ref = document.getElementById('AutoRefresh').checked;
clearInterval(handle);
if (ref)
handle = setInterval(function(){
document.getElementById('dataRefreshButton').click();
}, 2000);
window.alert("Auto refresh on");
}

Categories