How can I check and if exist stop javascript function?
I have a counting down JS code bottom;
function Countdown(options) {
var timer,
instance = this,
seconds = options.seconds || 10,
perTurn = options.perTurn || 1000,
updateStatus = options.onUpdateStatus || function() {},
counterEnd = options.onCounterEnd || function() {};
function decrementCounter() {
updateStatus(seconds);
if (seconds === 0) {
counterEnd();
instance.stop();
}
seconds--;
}
this.start = function() {
clearInterval(timer);
timer = 0;
seconds = options.seconds;
timer = setInterval(decrementCounter, perTurn);
};
this.stop = function() {
clearInterval(timer);
};
}
function CountDownToPlay(userID) {
var myCounter = new Countdown({
seconds: 20,
perTurn: 2000,
onUpdateStatus: function (sec) {
console.log(sec);
},
onCounterEnd: function () {}
});
myCounter.start();
}
It's counting down from more than 20 seconds, but manytime I must terminate the process...
How can I kill current javascript process? And check if it is exist?
DEMO:
http://jsfiddle.net/Ercin/gmt04nx9/
The object implements a stop function, why don't you just call it?
myCounter.stop();
To know if it exists should be easy enough since it's your code that's instanciating Countdown instances...
Typically unless you set up a flag somewhere, it is not possible to check if a javascript function is running somewhere.
However, if you need this information, you can set up a global variable and switch it on/off when your process starts / ends. You also should construct a global variable like "killProc" that the procedure checks on intermittently, and exits if it is true.
For more, check out Java's Thread.interrupt() concept.
Related
I was wondering if there is a nicer object oriented way of creating this timer? (without global vars!)
let secondsPassed = 0;
let timerId;
function startTimer() {
clearInterval(timerId);
timerId = setInterval(function() {
const seconds = twoDigits((Math.floor(secondsPassed )) % 60);
const minutes = twoDigits(Math.floor(secondsPassed / 60) % 60);
const hours = Math.floor(secondsPassed / 60 / 60);
$('#timer').text(`${hours}:${minutes}:${seconds}`);
secondsPassed++;
}, 1000);
$(window).blur(function() {
clearInterval(timerId) // stop timer when user leaves tab
});
$(window).focus(function() {
startTimer(); // continue timer when user comes back
});
}
Your current implementation is actually wrong. Every time you call startTimer, it installs startTimer as a new window focus event handler, leading to multiple started intervals when you focus the window the second time; growing exponentially. The onfocus handler should only run the timerId = setInterval(…) line - put that in a nested helper function to call only that.
This also makes it unnecessary to declare the variables globally.
function createTimer() {
let secondsPassed = 0;
let timerId;
function resume() {
if (timerId) return; // prevent multiple intervals running at the same time
timerId = setInterval(() => {
const seconds = twoDigits((Math.floor(secondsPassed )) % 60);
const minutes = twoDigits(Math.floor(secondsPassed / 60) % 60);
const hours = Math.floor(secondsPassed / 60 / 60);
$('#timer').text(`${hours}:${minutes}:${seconds}`);
secondsPassed++;
}, 1000);
}
function pause() {
clearInterval(timerId);
timerId = undefined;
}
$(window).blur(pause); // stop timer when user leaves tab
$(window).focus(resume); // continue timer when user comes back
resume(); // now start the timer
}
Now how to make that object-oriented? Just return an object from createTimer. Put resume and pause as methods on that object. Maybe add some more methods for starting, stopping, resetting, whatever you need. Maybe use a property on the object instead of the secondsPassed local variable. Or expose the local variable using a getter.
And to make it reusable, of course you can make createTimer accept arguments, from the selector of the output element, to the output element itself, to a callback function that will be called with the current time on every tick.
Edit: With this answer, you have to implement the Timer class yourself first. The code only shows how you could name the methods of the timer, how you create the instance and call its functions. The timer should (principle "separation of concerns") only handle the counting and provide the functionalities needed, like starting and stopping.
If you want to have an OOP solution for your timer, you shouldn't let the Timer class know the ID of the DOM container (like one of your comments to your question suggested).
You should read into the topic using this:
https://appdividend.com/2019/05/22/javascript-class-example-how-to-use-class-in-javascript-tutorial/
Let us assume, that you already implemented the class. Your code above should look like the following:
// Create own scope for the function, so that variable are not assigned to windows-object.
(function() {
let secondsPassed = 0;
let timer = new Timer();
// events, if necessary
timer.onTick((seconds) => { secondsPassed = seconds });
timer.onStop(() => { secondsPassed = 0; })
// Called by a button
function startTimer() {
timer.start();
}
// Example: Display alert with current timer seconds on click
function displaySecondsOfTimer() {
alert(timer.getSeconds());
}
$(window).blur(function() {
timer.stop(); // stop timer when user leaves tab
});
$(window).focus(function() {
timer.start(); // continue timer when user comes back
});
})();
So I think, you have a good example to code your first Timer class in native JavaScript! :)
Cannot terminate the setInterval I created in launch. It works until the time is up. I want to use clearInterval (interval) operation in next() function and prev() function. How should I do this? When I click forward, I want clearInterval(interval) to run this, but I couldn't.
function launch() {
thisTimeline = document.getElementsByClassName('story-active-' + start)[0];
var maxtime = 5000;
var incremental = 100;
var actualtime = 0;
var interval = setInterval(function() {
actualtime += incremental;
var percentage = Math.ceil((100 / maxtime) * actualtime);
thisTimeline.style.width = percentage + '%';
if (percentage == 100) {
clearInterval(interval);
thisTimeline.style.width = "0%";
}
}, incremental);
}
function next() {
// Set previous video timeline to 100% complete
thisTimeline.style.width = '100%';
// Advance play count to next video
start++;
// If next video doesn't exist (i.e. the previous video was the last) then close the Social Story popup
if (start >= defaults.playlist.length) {
setTimeout(function() {
close();
return false;
}, 400);
} else {
// Otherwise run the next video
launch(start);
}
}
function prev() {
if (start != 0) {
thisTimeline.style.width = '0%';
}
// Subtract play count to previous video
start--;
// If next video doesn't exist (i.e. the previous video was the last) then close the Social Story popup
if (start < 0) {
start = 0;
return false;
} else {
// Otherwise run the previous video
launch(start);
}
}
This is an extension of #lagoCalazans comment.
What he is saying is that in your variable "interval" is created in your launch function. You need to make "interval" global in order to clear your setInterval.
Ex:
let interval = null; //global
function launch() {
let tempInterval = setInterval(function() {
//whatever code
},100);
interval = setInterval(function(){
console.log("Hello");
}, 100);
}
function clear() {
//Since interval is global I can clear it when I call clear();
clearInterval(interval);
}
As you can see in the launch function "tempInterval" is limited to the scope of launch, therefore cannot be accessed anywhere else, but now since "interval" is global it can be accessed in any function.
Your code seems a bit incomplete, so for illustrative purposes only I will assume you encapsulate those functions in a higher order function (like an IIFE) and will avoid writing that (also, some kind of global state or variable would do for an example).
First of all, setInterval will return an id which you would use later, so if you want to use it within next and prev, you need that value to be available to them.
So, in your example, you should declare interval outside launch, and assign a value to it inside:
let interval
function launch() {
// ...
interval = setInterval(function() { ... })
}
and then use interval wherever you want.
launch, next and prev are three separate functions. They do not reference the same interval because they don't share scope. Raise the scope of the interval variable.
let interval = ''; // declared here, interval can be accessed by all functions
function launch() {
// ...
// remove the var before interval
interval = setInterval( ... )
}
function next() {
// ...
// remove the var before interval
interval = setInterval( ... )
}
function prev() {
// ...
// remove the var before interval
interval = setInterval( ... )
}
I'm a bit of a beginner with Javascript and am struggling to figure out how to use a function of one instance to trigger a function in another instance, and vice versa, both of the same class. Let me explain what I mean.
My project is to build a Pomodoro Clock in Javascript. Pomodoro is a process where you work for a specified time (25 minutes, for example), then take a short break (5 mins), and then repeat. The clocks should run back to back, indefinitely or until the user stops it.
I need the completion of one clock to trigger the beginning of the other one, and vice versa.
I built a working program using completely separate, slightly varying functions for each timer (with much redundancy). I tried to simplify my code by creating a class of Timers and building each one from that. That's where I've got stuck.
I have a function in my Timer class which, when the timer reaches zero, needs to call the other timer's countdown to begin (line 126 on Codepen). How can I do that?
Thank you for any help you can offer.
Here's my project on Codepen: https://codepen.io/lieberscott/pen/baRpgx?editors=1010
And my Javascript code below:
let session; // session Timer object instance
let btimer; // break Timer object instance
let s_off; // boolean for whether session timer is off or on
let s_timer; // reference to session timer HTML element
let s_stop; // reference to session stop HTML button
let s_increase; // reference to session increase HTML button
let s_decrease; // reference to session decrease HTML button
// same variables as above for break timer
let b_off;
let b_timer;
let b_stop;
let b_increase;
let b_decrease;
$(document).ready(function() {
s_off = true;
s_timer = $("#timer");
s_stop = $("#stop");
s_increase = $("#increase");
s_decrease = $("#decrease");
b_off = true;
b_timer = $("#breaktimer");
b_stop = $("#breakstop");
b_increase = $("#breakincrease");
b_decrease = $("#breakdecrease");
session = new Timer(1, 60, s_off, s_timer, s_stop, s_increase, s_decrease);
btimer = new Timer(5, 60, b_off, b_timer, b_stop, b_increase, b_decrease);
// increase session minutes
$(s_increase).on("click", function() {
if (session.off) {
session.min++;
session.sec = 00;
s_timer.html(session.min + ":" + session.sec);
}
});
// decrease session minutes
$(s_decrease).on("click", function() {
if (session.off) {
if (session.min > 1) {
session.min--;
}
session.sec = 00;
s_timer.html(session.min + ":" + session.sec);
}
});
// increase break minutes
$(b_increase).on("click", function() {
if (btimer.off) {
btimer.min++;
btimer.sec = 00;
b_timer.html(btimer.min + ":" + btimer.sec);
}
});
// decrease break minutes
$(b_decrease).on("click", function() {
if (btimer.off) {
if (btimer.min > 1) {
btimer.min--;
}
btimer.sec = 00;
b_timer.html(btimer.min + ":" + btimer.sec);
}
});
// begin session timer by clicking on the timer itself
$(s_timer).on("click", function() {
session.time();
});
// stop session timer
$(s_stop).on("click", function() {
session.off = true;
session.stopClock(session.intervalFunction);
});
// stop break timer
$(b_stop).on("click", function() {
btimer.off = true;
btimer.stopClock(btimer.intervalFunction);
});
});
class Timer {
constructor(min, sec, off, disp, stopButton, increaseButton, decreaseButton) {
this.min = min; // minutes
this.minsSet = min; // minutes again, this will be used to reset the timer
this.sec = sec;
this.off = off; // boolean saying whether timer is off or not
this.disp = disp; // HTML display
this.stopButton = stopButton;
this.increaseButton = increaseButton;
this.decreaseButton = decreaseButton;
this.func;
}
time() { // function fired when the timer is clicked
if (this.off) {
this.off = false;
this.func = this.intervalFunc();
}
}
intervalFunc() { // set the interval of the timer
setInterval(function() {this.countdown();}, 1000); // ERROR HERE
}
countdown() { // interval to complete for duration of timer
// check if clock reaches zero
if (this.sec == 0) {
this.min--;
this.sec = 60;
if (this.min < 0) {
this.min = this.minsSet;
this.sec = 0;
this.off = true;
this.time(); // this needs to trigger, not this.time(), but the OTHER object's time() function
this.stopClock(this.func); // clearInterval() function below
}
}
// if clock is not at 0:00, display new time
this.sec--;
let m = this.min.toString();
let s;
if (this.sec < 10) {
s = "0" + this.sec.toString()
}
else {
s = this.sec.toString();
}
this.disp.html(m + ":" + s);
}
stopClock() {
clearInterval(this.func);
}
}
1) I tried your code and fixed some bugs, your setInterval issue is because "this" points to window object there.
2) for calling the other object time() method, first off you need something to know which object you are working with, so I have added a type variable to the class and then in the countdown function i have added a check.
Changes are in this pen :
https://codepen.io/yaduvanshi/pen/dJRdeR?editors=0010
intervalFunc() { // set the interval of the timer
var that =this;
setInterval(function() {that.countdown();}, 1000); // ERROR HERE
}
I think the solution that you are looking for, is the .bind() or the .call() that Javascript provides you with (Function.prototype.bind()). For example, the .bind() function takes the specific object instance as argument. You can read up on the same here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
I am working on a modification of tamper data that will allow me to send the HTTP request/responses it observes to a server. So far, that functionality has been implemented correctly. The next step is to automate this process, and I wish to use a toolbarmenu button of type 'checkbox' to toggle this functionality on and off.
So far I have this bit of code in the .XUL:
<toolbarbutton id="tamper.autosend" label="&tamper.toolbar.autosend;" type="checkbox" oncommand="oTamper.toggleTimer();"/>
And this function in the main driver of my extension:
toggleTimer : function() {
var checked = document.getElementById('tamper.autosend').checked;
var consoleService = Components.classes["#mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(checked);
if (checked) {
var interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
}
Using the consoleService I see that the value of 'checked' is indeed correct. I believe the problem lies with how I am calling clearInterval, but I'm not exactly sure how to remedy it.
Any help is greatly appreciated!
You have defined interval inside if try to declare your variable on the start
var interval = 0;
toggleTimer : function() {
var checked = document.getElementById('tamper.autosend').checked;
var consoleService = Components.classes["#mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(checked);
if (checked) {
interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
}
Your doing it wrong, each time you want to set the new interval you should clear it first
clearInterval(intervalID);
console.log('reset timer');
intervalID = setInterval(function () {
console.log('tick');
}, refreshInterval);
You're storing the interval in a local variable; the value is lost after the function returns, next time you attempt to clearInterval an undefined variable. Store the interval in i.e. a global variable instead:
if (checked) {
window.interval = window.setInterval(function(thisObj) { thisObj.sendResults(true); }, 1000, this);
}
else {
window.clearInterval(interval);
}
Ofcourse, because interval is defined as a private variable. It is defined in the toggleTimer function and is destroyed when the function ends.
Use interval = window.setInterval() instead of var interval = window.setInterval() to define a global variable that is accessible later for clearInterval.
Below are some examples of the JavaScript variable scope. var is used to define a variable in the current scope. Leaving var always creates or changes a local variable.
function func1() {
i = 1; // global
}
func1();
alert(i); // 1
var j = 2;
function func2() {
var j = 3; // private
}
func2();
alert(j); // 2
k = 4;
function func3() {
k = 5; // global
}
func3();
alert(k); // 5
var l = 6;
function func4() {
l = 7; // global
}
func4();
alert(l); // 7
function func5() {
var m = 6; // private
}
func5();
alert(m); // undefined
For instance, I am setting an interval like
timer = setInterval(fncName, 1000);
and if i go and do
clearInterval(timer);
it does clear the interval but is there a way to check that it cleared the interval? I've tried getting the value of it while it has an interval and when it doesn't but they both just seem to be numbers.
There is no direct way to do what you are looking for. Instead, you could set timer to false every time you call clearInterval:
// Start timer
var timer = setInterval(fncName, 1000);
// End timer
clearInterval(timer);
timer = false;
Now, timer will either be false or have a value at a given time, so you can simply check with
if (timer)
...
If you want to encapsulate this in a class:
function Interval(fn, time) {
var timer = false;
this.start = function () {
if (!this.isRunning())
timer = setInterval(fn, time);
};
this.stop = function () {
clearInterval(timer);
timer = false;
};
this.isRunning = function () {
return timer !== false;
};
}
var i = new Interval(fncName, 1000);
i.start();
if (i.isRunning())
// ...
i.stop();
The return values from setTimeout and setInterval are completely opaque values. You can't derive any meaning from them; the only use for them is to pass back to clearTimeout and clearInterval.
There is no function to test whether a value corresponds to an active timeout/interval, sorry! If you wanted a timer whose status you could check, you'd have to create your own wrapper functions that remembered what the set/clear state was.
I did this like below, My problem was solved. you should set the value like "false", when you clearTimeout the timer.
var timeer=false;
----
----
if(timeer==false)
{
starttimer();
}
-----
-----
function starttimer()
{
timeer_main=setInterval(activefunction, 1000);
timeer=true;
}
function pausetimer()
{
clearTimeout(timeer_main);
timeer=false;
}
Well you can do
var interval = setInterval(function() {}, 1000);
interval = clearInterval(interval);
if (typeof interval === 'undefined'){
...
}
but what are you actually trying to do? clearInterval function is an always success function and it will always return undefined even if you call it with a NaN value, no error checking in there.
You COULD override the setInterval method and add the capability to keep track of your intervals. Here is an untestet example to outline the idea. It will work on the current window only (if you have multiple, you could change this with the help of the prototype object) and this will only work if you override the functions BEFORE any functions that you care of keeping track about are registered:
var oldSetInterval = window.setInterval;
var oldClearInterval = window.clearInterval;
window.setInterval = function(func, time)
{
var id = oldSetInterval(func, time);
window.intervals.push(id);
return id;
}
window.intervals = [];
window.clearInterval = function(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == id)
{
window.setInterval.intervals.splice(i, 1);
}
oldClearInterval(id);
}
window.isIntervalRegistered(id)
{
for(int i = 0; i < window.setInterval.intervals; ++i)
if (window.setInterval.intervals[i] == func)
return true;
return false;
}
var i = 0;
var refreshLoop = setInterval(function(){
i++;
}, 250);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
clearInterval(refreshLoop);
if (isIntervalRegistered(refrshLoop)) alert('still registered');
else alert('not registered');
The solution to this problem: Create a global counter that is incremented within your code performed by setInterval. Then before you recall setInterval, test if the counter is STILL incrementing. If so, your setInterval is still active. If not, you're good to go.