Chrome extension - Variable value not assigned deppending on interval duration - javascript

The title sums up the weird problem I am having. I declare a global variable, execute a setInterval function which modifies that variable and deppending on the duration of the interval, the variable will look modified or not.
To be more clear, this simple background file code illustrates the situation:
var TabId=0;
var target= "https://google.com";
function start() {
chrome.tabs.create({url: target}, function(tab) {TabId=tab.id;});
setInterval(Repeat, 30*1000); //repeat every 30 seconds
}
function Repeat(){
chrome.tabs.remove(TabId);
chrome.tabs.create({url: target}, function(tab) {TabId=tab.id;});
}
chrome.browserAction.onClicked.addListener(start);
I am surprised that for "short" intervals such as 10 seconds, the extension works just fine, but for 30 seconds, for example, it fails. It does nothing after the specified time is elapsed, and if you check in the console the value of TabId, it is still 0. It looks as if the code line
TabId=tab.id;
has never been executed, which is impossible because the tab has been created, right?
But there is something more: if you open the console for the background page before even firing the onClicked event, it seems to run ok as expected!
Can anybody help me understand what is going on here?
At first I thought it could have to do with the variable scope, but it doesn't make sense because for shorter intervals it works perfectly.
Regards.

My bad.
In my manifest file I had set "persistent" to false. This property enables you to work with an event page instead of a background page.
Event pages are loaded only when they are needed. When the event page is not actively doing something, it is unloaded, freeing memory and other system resources.
So, after a while waiting for the interval to complete, the TabId is erased.
It was driving me crazy, but this morning I woke up with a hint for the solution.

Related

Why would 'clearTimeout' not work in this scenario?

I'm having an issue stopping the 'gameTimer' timer from running with 'clearTimeout()' in my code. I have simplified part of my code here to only contain the necessary details.
//This runs when someone connects to my website
io.on('connection', function (socket) {
let gameTimer;
//Runs the in-game timer
function questionCountdown() {
gameTimer = setTimeout(function () {
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}, 21000)
}
//Starts the game
socket.on('Request Game Start', async function (room) {
questionCountdown();
})
//Runs when a player has answered(ignore the function arguments)
socket.on('Answered Question', function () {
//If all users in the room have answered...
if (answeredPlayers.get(playerData[socket.id].room) == (roomMap.get(playerData[socket.id].room)).length) {
//Stop the count[THE MAIN ISSUE]
clearTimeout(gameTimer);
//Reveal if the players' answers are right or wrong
revealAnswer(answeredPlayers, playerData[socket.id].room);
//Start the countdown for the next question
countToNextQuestion(playerData[socket.id].room);
}
})
})
Is there any reason why the "clearTimeout()" used in socket.on('Answered Question', function () {would not work?
Possible reasons that the clearTimeout() doesn't stop a previously started gameTimer:
The socket.on('Answered Question', ...) event isn't happening when you think it is. Either it's never happening or it's happening too soon.
The condition if (answeredPlayers.get(playerData[socket.id].room) == (roomMap.get(playerData[socket.id].room)).length) isn't being met or throws and thus you never get to the clearTimeout().
You start more than one gameTimer for a given user before stopping one, thus the second overwrites the timer from the first and you then never stop the first one.
Your user leaves the web page or hits refresh and since you don't show listening for the disconnect event, you leave a gameTimer running that can never get stopped. FYI, this should be addressed whether it's the cause of the current problem you're looking at or not.
Since each socket.io connection has their own gameTimer, you are just confused about whether it is or isn't getting stopped and perhaps one gameTimer is getting stopped and you're just being fooled by the fact that there are others also running that belong to different connections.
FYI, you can figure out if any of these are the cause with appropriate console.log() statements and then studying the logs. These timing-sensitive, event driven problems are usually solved with detailed logging and then studying the logs to see exactly what did and didn't happen in your code and in what order.
In your code since the setting of the Timeout is triggered by an event, it might occur that clearTimeout get's called without gameTime being set. Also clearTimeout is being triggered by an event and if that event doesn't fire the timeout won't be cleared.
The problem might lie in the source of your events. Where or when do they get triggered?
You might also test your if statement. Put a console.log before calling clearTimeout and see if it get's run when you want it to.

Odd Javascript behavior: Iterative changes to Div ignored unless Alert is present

My code includes a function with a lengthy For loop. Near the end of the loop is a code line that, with each iteration, increases the width of a div that serves as a status bar. The problem? The status bar's width only increases if there is an alert line above it to alert me of the current loop counter. When I comment out that alert, the web page freezes, I hear a lot of computer whirring, and eventually I get a A web page is slowing down your browser. What would you like to do? browser message. The function is outlined below:
function processData(dataArr) {
// initialize the status bar
var bar = document.createElement('div');
bar.setAttribute("style","top:7px;left:125px;height:25px;width:400px");
bar.id="StatusBar";
document.body.appendChild(bar);
// now start the loop:
for (var i=0;i<dataArr.length;i++) {
// do a lot of string manipulation and parsing on dataArr[i]
// update the status bar every 50 iterations
if (Math.ceil(i/50) == Math.floor(i/50)) {
alert('Loop # '+(i+1)); // If this line is commented out, the status bar stops updating!
}
bar.style.width = Math.round(((1+i)/dataArr.length)*400)+'px';
}
// loop has finished last iteration, remove status bar
document.body.removeChild(bar);
}
The alert line noted above is the line whose presence makes the difference between the code functioning normally (data gets processed, the status bar grows with loop counter) or the web page freezing and getting a web page is slowing down your browser warning. Can anyone explain why a seemingly benign alert line would so dramatically change the functionality of this code?
The following fact is likely irrelevant, but just in case it isn't: the above function is called from within an onload: function() code block of a xmlhttpRequest in a second function.
Updated: I just found another possibly-related stackoverflow question which suggests maybe the underlying cause is that this function is called from within the onload block of an xmlhttpRequest. The answers to that question do not provide a solution to my problem, however, and the questions do not deal with quite the same topic (I am using a userscript, and page-loading does not seem to be the problem, as I am able to generate the initial status bar without any difficulty. With the exception of updating the status bar at the end of each loop, no web page manipulation is being conducted within the loop.)
2nd update: corrected so that the brackets are correctly closed
When inside a for loop, the presence of a seemingly innocuous alert allows a CSS command to immediately change a div (the div change command immediately follows the alert inside the loop) with each the loop increment because the alert command invokes the event loop to wait for a response from the user (e.g., hitting the OK button on the alert box). During this wait, the DOM changes can be rendered. Without the alert command (or some alternative way such as timers to explicitly cause real-time DOM change rendering), changes are not rendered on the web page until all Javascript functions are complete and the code's execution has returned to the browser's main event loop. In my case, this point in the code would be when the function returned to the second function that called it, within the onload: block of an xmlhttpRequest.
An explicit illustration of this behavior: while the CSS command to increase div width was supposed to occur at the end of each for loop increment, the div (serving as a status bar) instead only grew on every 50th loop iteration, the same frequency that the alert was coded to execute. To satisfy the need for a status bar to show data processing progress, I restructured the work flow in my code: instead of waiting until all chunks of data from the second function's xmlhttpRequest had been downloaded before calling the above function, I called the above function to process each chunk of data as it was downloaded. The status bar that was working well within the xmlhttpRequest block now represents the combined download and processing of the data.

setTimeout firing too soon(?)

Alright, right now I'm writing a little JavaScript code that I can just simply copy paste into the Firefox Console and run. (I'm sorry, I'm still a massive noob, and I want to write a little script that basically, opens a certain web page and collects information form certain divs in it.)
However, I'm struggling at the moment. I would like to open a certain webpage, and then, after it is entirely loaded, execute a certain function. (for simplyfying reasons, this function just counts from 0 to 99.)
function openGroupsPage() {
window.location.replace(groupURL);
setTimeout(function() {
for (i = 0; i < 100; i++) {
console.log(i)
}
} , 10000)
}
openGroupsPage()
My problem is : The incrementing function never gets called (or atleast it seems like it because i can never see any kind of output in the console.) Why is my setTimeout not working or what is another option to accomplish what I would like to do? I would just really like to run a specific function when the newly accessed website is finished loading entirely.
When you change the location, the window object and all of its associated things (including timers) are discarded and a new one created. You can't schedule code to run in the new document from within the old document (not even from the browser console). You'll have to paste and execute your code after navigating to the new page, not before, which means you can't navigate to it from within your code.
You might look at tools like TamperMonkey or GreaseMonkey and such that let you run code in response to pages loading that match certain URLs.
window.location.replace() exits the current page and loads a new one. So any remaining JavaScript of the current page isn't executed anymore
Your function is working fine the only problem is window.localtion line reload the website with the url you provided so the entire page is getting reload from start and your page lost your function.
try the below to understand
function openGroupsPage() {
//window.location.replace('http://www.google.com');
setTimeout(function() {
for (i = 0; i < 100; i++) {
console.log(i)
}
} , 1000)
}
openGroupsPage()
You could add an eventListener do the document of the page which fires when the page is loaded.
document.addEventListener('DOMContentLoaded' function(e) {
// page is loaded do you fancy stuff in here
// no timeout needed
});
EDIT: Overlooked that he want to do it over the console on a random page. This won't work because on locationchange all current scripts are stopped and global objects are destroyed.
Use something like Greasemonkey for that.

how to disable a timeout on the page source level?

i am opening a page on the chrome by using F12, and i realize it do have a timer inside the source code, however, the timer started on the page load and it does not store the timer as a variable, what the source code use is
self.setTimeout("OnReload()", 60000);
so if i am intend to using window.clearTimeout(timer);
Since it is not store as a variable, i am not able to using this method to clear the timeout variable, may i ask am i able to clear this timeout???
As you cannot disable the timer, why not just overload the function i.e.
function OnReload() { }
So that it does nowt.
the answer is i key in self.clearTimeOut(0);
and it work

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.

Categories

Resources