I have the following javascript.
function isOnline() {
var status = navigator.onLine ? 'online' : 'offline',
indicator = document.getElementById('indicator'),
current = indicator.textContent;
// only update if it has change
if (current != status) {
// update DOM
indicator.textContent = status;
// trigger handler
handler[status]();
};
if(current == 'offline')
{
setInterval(checkServerStatus, 500)
checkServerStatus();
}
};
function checkServerStatus()
{
var img = document.createElement("img");
img.onload = function()
{
alert('yey!');
setInterval(isOnline, 500);
isOnline();
};
img.onerror = function()
{
alert('meh.')
};
img.src = "image-small.jpg"; //image on server(should be small so that intermittent checks are not bad)
}
$(checkServerStatus);
What I'd like to do is the following.
First call checkServerStatus() -- > if online run isOnline() every 500ms to keep checking the status of the website. In my isOnline code if I ever check that it is offline, then run checkServerStatus again, and if I'm still connected go back.
In addition, I'd like to add two things to this, when checkServerStatus fails, recursively call another function isOnline2 to check until it is online, where I then call checkServerStatus again.
The issue I am currently running into right now is that checkServerStatus keeps showing the 'yey' alert. I thought that, the function only starts once, and then using setInterval(isOnline, 500) will continue to run. After isOnline changes to offline, then I would run my checkServerStatus function again.
Any ideas on how to adjust this would be extremely appreciated.
Set your interval to a variable and then use clearInterval() when you want to stop your interval.
var interval = setInterval();
clearInterval(interval);
setInterval() runs a function on an interval endlessly, until cancelled with clearInterval().
In your case, I'd actually suggest not using setInterval but instead use setTimeout. This allows better control of execution: setTimeout runs once. At the completion of each function, you should be calling setTimeout to invoke either checkServerStatus or isOnline, as appropriate.
function isOnline() {
.....
if(current == 'offline') {
setTimeout(checkServerStatus, 500);
} else {
setTimeout(isOnline, 500);
}
};
It also prevents overlap: if, for example, checkServerStatus takes more than 500 ms to complete, with setInterval you'll be running it multiple times at the same time.
Related
I have an angular 6 strange problem.
I am using setTimeout and clearTimeout functions to start/cancel the timeout.
However this sometimes works, and sometimes doesn't.
Even if the user triggers an (click) event and the clearTimeout is run, sometimes it forces player to draw two cards.
Here is the code
//an event that says we must call uno
this._hubService.mustCallUno.subscribe(() => {
this.mustCallUno = true;
this._interval = window.setInterval(() => {
this.countdown -= 100;
}, 100);
this._timer = window.setTimeout(() => {
if (this.mustCallUno) {
this.drawCard(2);
this.callUno();
}
}, 2000);
});
// a function player calls from UI to call uno and not draw 2 cards
callUno() {
this.mustCallUno = false;
window.clearTimeout(this._timer);
window.clearInterval(this._interval);
this.countdown = 2000;
}
So even if the player calls callUno() function, the setTimeout is executed. Even worse, the code goes through the first if check inside the setTimeout if( this.mustCallUno) which by all means should be false since we just set it to false when we called callUno() function this.mustCallUno = false;.
I used setTimeout (returns NodeJS.Timer) before window.setTimeout and the result was the same.
You're using angular6+, so I suggest you to use reactive programming library such as rxjs
I made you a small example here.
Check for the possibility where function in this._hubService.mustCallUno.subscribe is run twice or multiple times, usually initially which you might not be expecting. Put a logger in function passed to mustCallUno.subscribe and callUno.
In this case what might be happening is this._timer and this._interval will have a different reference while the old references they hold, were not cleared because callUno is not called or is called less number of times than the callback in subscribe.
I'm making a quiz-type app in which, when user gets a question, a timer of 10 seconds goes like this:
$scope.timer2 = function() {
setTimeout(function() {
console.log('times up!!!!');
}, 10000)
}
and it is being called when a question arrives like this:
timerHandle = setTimeout($scope.timer2());
And after this timer2 execution another question pops up and so on, another way of a question being popped up is that the user selects an option also then a new question comes up. So far so good but the problem is that if suppose 5 seconds were passed and then user selects an option, the "timer2" still shows "times up!!" after 5 more seconds and another timer for the new question also shows "times up!!" if the user hasn't selected any option.
What I'm trying to say is that I want the timer2 to stop when user selects any option, and then i want again this timer to be called as a new question will arrive.
This is the angular code which executes when user selects an option:-
$scope.checkanswer=function(optionchoosed){
$http.get('/quiz/checkanswer?optionchoosed='+ optionchoosed).then(function(res){
if(res.data=="correct"){
$scope.flag1=true;
$scope.flag2=false;
}else{
$scope.flag2=true;
$scope.flag1=false;
}
$http.get('/quiz/getquestions').then(function(res){
console.log("respo");
$scope.questions=res.data;
clearTimeout($scope.timerHandle); //not working
timerHandle = setTimeout($scope.timer2());
You can try using the service of AngularJS $timeout.
Then do something along these lines:
var myTimer = $timeout(function(){
console.log("hello world")
}, 5000);
....
$timeout.cancel(myTimer);
Take a look at the MDN documentation for setTimeout.
As you can see, that function returns a unique identifier.
At this point, you can call clearTimeout passing that UID as parameter:
let myTimeout = setTimeout(myFunction, millis); //Start a timeout for function myFunction with millis delay.
clearTimeout(myTimeout); //Cancel the timeout before the function myFunction is called.
Since you do not provide working example let me do the best guess. Your function does not return handle from inner setTimeout so it cannot be cancelled. What about such modifications:
$scope.timer2 = function() {
return setTimeout(function() { // added return statement
console.log('times up!!!!');
}, 10000)
}
and then
timerHandle = $scope.timer2(); // simply call timer2 that returns handle to inner setTimeout
So I'm attempting to make a Pomodoro Timer without using an API (I know, stupid choice) but I feel as if I'm over-complicating this issue.
I forked my CodePen so I could post the current code here without confusing anyone. My Code Pen
To see my issue: Just set Timer to .1 and Break to .1 - You'll see the Start to Resume works fine, but the Resume to start has issues.
I built in consoleLogs to track it and I see the Work Timer TRIES to start but then breakTimer over-runs it, and duplicates on every pass.
Why isn't my clearInterval working?
Things I've tried:
Adjusting names of clearInterval,
Setting it so it goes back to startTimer instead of start
force quitting it (instead of looping it back to startInterval.
The function is virtually identical to my startFunction yet fails to work properly. Would appreciate any input (I'm new to clearInterval but I believe I am using it right.)
function breakTimer() {
$('.jumbotron').css('visibility', 'visible');
setInterval(function() {
console.log("Break Timer...");
breakTime--;
if (breakTime < 0) {
clearInterval(timer);
working = false;
start();
} else {
showTime(breakTime);
}
}, 1000);
}
Edit:
To answer the reply:
function start() {
if (working == true){ //This keeps it from being spammable
return;
} //Else
workTime = $('#work').val()*60;
breakTime = $('#break').val()*60;
working = true;
checkStatus();
timer = startTimer();
}
Unsure if I should post every Function here
As per definition, the value returned by setInterval(...) is the ID of the created timer. As such, with your code you can only stop the last created timer because the ID in the timer variable gets overwritten, causing it to lose control over the previously created (and still running) timers.
The ID is what you pass on to clearInterval(...) to stop a timer. You will have to do this in a different way. You may ask for a different way in https://codereview.stackexchange.com/
I'm having an issue with a javascript requirement. I have a html calling a script perpetually every 1500ms using setInterval.
var t = setInterval(loadData(),1500);
The loadData function calls a script which returns a JSON as a list, what I want to do is to change from a fixed interval to a variable interval. For instance, if there are no changes made between two calls to the script, I must set another value for the interval. I heard I could use jquery linq to compare the length of the list at the beginning and the list when refreshing to change the time value. I also heard I could save the value of count in a cookie to compare always.
Any idea please? I would be grateful. Thanks in advance.
I'm guessing you're trying to do:
var speed = 1500,
t = setInterval(loadData, speed);
function loadData() {
if (something == true) {
something = false;
speed = 3000;
clearInterval(t);
t = setInterval(loadData, speed);
}else{
//do something
}
}
You should just reference the function, adding the parenthesis runs the function immediately. When using a variable for the speed, you'll need to clear and run the interval function again to change the speed.
if the interval is variable, then you can't use setInterval, which period won't be changed after the first call. You can use setTimeout to alter the period:
var period=1500
var timer;
var callback = function() {
loadData();
timer = setTimeout( callback, period )
};
var changePeriod = function( newPeriod ) {
period = newPeriod;
}
//first call
callback();
now, you just need to call changePeriod( ms ) to change the period afterwards
I am not too familiar with the specifics of every javascript implementation on each browser. I do know however that using setTimeout, the method passed in gets called on a separate thread. So would using a setTimeout recursively inside of a method cause its stack to grow indefinitely until it causes a Stack Overflow? Or would it create a separate callstack and destroy the current frame once it goes out of focus? Here is the code that I'm wondering about.
function pollServer()
{
$.getJSON("poll.php", {}, function(data){
window.setTimeout(pollServer, 1000);
});
}
window.setTimeout(pollServer, 0);
I want to poll the server every second or so, but do not want to waste CPU cycles with a 'blocking loop' - also I do not want to set a timelimit on how long a user can access a page either before their browser dies.
EDIT
Using firebug, I set a few breakpoints and by viewing the "Script -> Stack" panel saw that the call stack is literally just "pollServer" and it doesn't grow per call. This is good - however, do any other implementations of JS act differently?
I am not sure if it would create a stack overflow, but I suggest you use setInterval if the period is constant.
This is how prototype implements its PeriodicalExecuter.
// Taken from Prototype (www.prototypejs.org)
var PeriodicalExecuter = Class.create({
initialize: function(callback, frequency) {
this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
execute: function() {
this.callback(this);
},
stop: function() {
if (!this.timer) return;
clearInterval(this.timer);
this.timer = null;
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.execute();
} finally {
this.currentlyExecuting = false;
}
}
}
});
setTimeout executes sometime later in the future in the event pump loop. Functions passed to setTimeout are not continuations.
If you stop and think about it, what useful purpose or evidencec is there that the call stack is shared by the timeout function.
If they were shared what stack would be shared from the setter to the timeout function ?
Given the setter can do a few returns and pop some frames - what would be passed ?
Does the timeout function block the original thread ?
Does the statement after the setTimeout function execute after the timeout executes ?
Once you answer those questions it clearly becomes evident the answerr is NO.
setTimeout does not grow the callstack, because it returns immediately. As for whether your code will run indefinitely in any browser, I'm not sure, but it seems likely.
take a look at the jQuery "SmartUpdater" plugin.
http://plugins.jquery.com/project/smartupdater
Following features are available:
stop() - to stop updating.
restart() - to start updating after pause with resetting time interval to minTimeout.
continue() - to start updating after pause without resetting time interval.
status attribute - shows current status ( running | stopping | undefined )
updates only if new data is different from the old one.
multiplies time interval each time when data is not changed.
handle ajax failures by stopping to request data after "maxFailedRequests".