clearInterval from an outside function (Vanilla Javascript) - javascript

I know that this question has been asked before on this platform, but I am really unable to implement the same thing that this friend implemented *(I mean Roy's answer).
How will I pause the timer, mean (clear interval) from an outside function?
according to my algorithm the function checkAnswer (should) be out side of the fetchQuesiton() function, It's not a big problem if it was inside but it's better for me to be outside, Help as much as you can.
[edit] more explain:
let's imagine that a player is playing this game, so when the timer reaches to 0, and the player until now didn't choose any answer, it will then clear that timer and then move to the checkAnswer function, which will then check for no answer, this means (in the future, when I make it) that it (checkAnswer) will return false, mean the answer is incorrect.
another case, is when the player chooses an answer, it will pauses that setInterval timer, and check for the answer if it was correct or incorrect.
function theCallerFunction() {
fetchQuesiton();
//this is just an overview from a code I am writing.
}
var fetchQuesiton = async() => {
//this function should be async because later it will check a value responded by a promise.
//start timer
let timer = 15;
const startTimer = setInterval(() => {
timer--;
console.log(timer);
if (timer == 0) {
clearInterval(startTimer);
console.log("TIMEUP! YOU'RE LOSER!");
checkAnswer();
}
}, 1000);
//[click] on chances
let options = document.querySelectorAll('.option');
options = Array.prototype.slice.call(options);
options.forEach(cur => {
cur.addEventListener('click', checkAnswer);
});
}
var checkAnswer = async() => {
//this function should be async because later it will check a value responded by a promise.
clearInterval(startTimer);
console.log("I am working!");
}
theCallerFunction();
<div class="option">a)</div>
<div class="option">b)</div>
<div class="option">c)</div>
<div class="option">d)</div>

The variable startTimer inside the checkAnswer function block doesn't refer to the same value as startTimer inside the fetchQuesiton.
Move startTimer out of fetchQuestion so that both variable call refer to the same value.
let startTimer
var fetchQuesiton = async() => {
...
startTimer = setInterval(() => {
Variables in javascript is lexically scoped. Read more here What is lexical scope?

Move startTimer to the global scope - or at the very least, a greater scope.
function theCallerFunction (){
fetchQuesiton();
//this is just an overview from a code I am writing.
}
let startTimer;
var fetchQuesiton = async ()=>{
//this function should be async because later it will check a value responded by a promise.
//start timer
let timer = 15;
startTimer = setInterval(()=>{
timer--;
console.log(timer);
if(timer == 0){
clearInterval(startTimer);
console.log("TIMEUP! YOU'RE LOSER!");
checkAnswer();
}
},1000);
//[click] on chances
let options = document.querySelectorAll('.option');
options = Array.prototype.slice.call(options);
options.forEach(cur=>{
cur.addEventListener('click', checkAnswer);
});
}
var checkAnswer = async () => {
//this function should be async because later it will check a value responded by a promise.
clearInterval(startTimer);
console.log("I am working!");
}
theCallerFunction();
<div class="option">a)</div>
<div class="option">b)</div>
<div class="option">c)</div>
<div class="option">d)</div>

Related

Trying to use setInterval to make a throttling function unsuccessfully

I am trying to return a function that only invokes a callback function 'func' once per every 'wait' milliseconds.
Additional calls to the callback 'func' within the 'wait' period should NOT be invoked or queued.
This is what I have so far...
function throttle(func, wait) {
function inner(...args) {
setInterval(func(...args), wait);
}
return inner;
}
When I run the code through the test algorithm I get the following errors:
"throttled functions should only be able to be called again after the specified time"
Here is the testing algorithm...
let counter = 0;
const incr = () => counter++;
const throttledIncr = throttle(incr, 32);
throttledIncr();
throttledIncr();
setTimeout(() => {
expect(counter).to.eql(1);
throttledIncr();
setTimeout(() => {
expect(counter).to.eql(2);
done();
}, 32);
}, 32);
"throttled functions return their value"
Here is the testing algorithm...
let counter = 0;
const incr = () => ++counter;
const throttledIncr = throttle(incr, 32);
const result = throttledIncr();
setTimeout(() => {
expect(result).to.eql(1);
expect(counter).to.eql(1);
done();
}, 64);
"throttled functions called repeatedly should adhere to time limitations"
Here is the testing algorithm...
const incr = () => ++counter;
const throttledIncr = throttle(incr, 64);
const results = [];
const saveResult = () => results.push(throttledIncr());
saveResult();
saveResult();
setTimeout(saveResult, 32);
setTimeout(saveResult, 80);
setTimeout(saveResult, 96);
setTimeout(saveResult, 180);
setTimeout(() => {
expect(results[0]).to.eql(1);
expect(results[1]).to.be(undefined);
expect(results[2]).to.be(undefined);
expect(results[3]).to.eql(2);
expect(results[4]).to.be(undefined);
expect(results[5]).to.eql(3);
done();
}, 192);
My questions regarding each case:
How do I prevent the function from being called again ?
Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.
What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error. There isn't any mention of setting a time limit so I don't believe using setTimeout here is what they mean...
How do I prevent the function from being called again ?
function throttle(func, wait) {
function inner(...args) {
setInterval(func(...args), wait);
}
return inner;
}
First, your code above does not do what you expect it to do. Currently every time you invoke throttle, you are adding func to the event loop, to be executed on an interval.
So when you call throttleIncr 5 times, you are adding incr to the eventloop to be called five times.
One approach (imo), would be to keep track of the last time that throttle(func) was invoked. The next time throttle(func) is invoked, check to see if the wait time has elapsed. If so, invoke func and save off the new time. If not, return.
Why ISNT my function returning value? I can't deduce what or how to return a value with the given testing algorithm.
Your incr function, IS returning the value, however your throttle function puts it on the eventloop, for asychronous execution, so the return value is not available.
What does "throttled functions called repeatedly should adhere to time limitations" even mean? This seems contradictory to the first error.
This is not a javascript error, and likely a custom failure message from the tests you are invoking.
I tried something here, that seems to be working:
function throttle2(callback, delay = 1000) {
let interval;
let currentArgs;
return (...args) => {
currentArgs = args;
if (!interval) {
interval = setInterval(() => {
if (currentArgs) {
callback(...currentArgs);
currentArgs = null;
} else {
clearInterval(interval);
interval = false;
}
}, delay);
}
};
}
Sandbox: https://codesandbox.io/s/competent-tereshkova-ccop2e?file=/index.js:167-179

How can I alert an asynchronous function that another instance of the same function has fired?

I am wanting to create an alert inside my function which tracks if any other instances of the same function have fired during a 15 second period. this is what I have so far:
bar = 0;
async function Counting() {
bar += 1;
foo = bar;
new Promise(resolve => setTimeout(resolve, 5000));
if (bar == foo) {
//Do something
}
else {
return;
}
}
I'm using bar as a global counter and foo as a function instance counter, but for some reason all instances of the function update at the same time.
How can I check if this function has fired during the 15 second waiting period and then stop all previous instances of the function if this is the case?
Earlier today I asked a question similar to this and someone by the username of #FedericoMoretti was able to help me out. He suggested using let and const variables which did the trick in my specific case.
let bar = 0;
async function Counting() {
bar += 1;
const foo = bar;
new Promise(resolve => setTimeout(resolve, 5000));
if (bar == foo) {
//Do something
}
else {
return;
}
}
I feel like your solution is a bit overly complicated. I think what you're describing is function debouncing:
It can be a little harder to explain. With debouncing, it’s like “Hey, I’m not going to execute that function until I know there are no more changes inbound”. We don’t execute our function until everyone else is happy and we’re clear to proceed. Imagine ordering food at a restaurant. You start listing off items to the waiter/waitress and at the end they ask “Is that everything?” If it is, they leave you to it and go get your food and drinks. If it isn’t, you add to the order and then they ask you again until they are clear to proceed.
- Throttling and Debouncing in JavaScript - Jhey Tompkins
- https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf
Basically something like this:
const fn = (() => {
let timer = null;
const myFn = () => {
timer = null;
console.log('My fn has been ran!');
};
return () => {
if(timer != null){
clearTimeout(timer);
}
timer = setTimeout(myFn,5000);
};
})();
This way when you call your function, it will wait 15 seconds to run the actual logic. However, if the function is called again within that 15 seconds, the timer restarts.
Usually for something like this you use a library function to do it so you don't have to write all this boilerplate each time:
function debounce(fn,time){
let timer = null;
return function(...args){
if(timer != null){
clearTimeout(timer);
}
timer = setTimeout(fn.bind(this,...args),5000);
};
}
// Usage
const myFn = debounce((name) => {
console.log('Hello %s!',name);
},1000);
// This function won't output "Hello !"
myFn('Joe');
// This function will
myFn('John');

Calling class methods inside javascript class

This is a Vue class. The method signOut() should fire when the timer ticks. The timer works, except the call signOut().
The problem is with accessing the class method. I'm confused with this, self and access modifiers.
I tried with this.signOut() but it does not work.
How can I call the method signOut?
"use strict";
(async (globals, config, loader, application) => {
const storageLocal = await loader.services.storage.local.getAsync();
class HeaderComponent {
#foo = a;
constructor(tag) {
this.tag = tag;
this.timer();
}
signOut() {
storageLocal.delete('account');
window.location = '/signin.html';
}
timer() {
//document.getElementById("timer"),
var counter = -1;
var timeout;
var startTimer = function timer() {
counter++;
console.log(counter);
signOut(); //<- error can't call class method
timeout = setTimeout(timer, 10000);
};
function resetTimer() {
// here you reset the timer...
clearTimeout(timeout);
counter = -1;
startTimer();
//... and also you could start again some other action
}
document.addEventListener("mousemove", resetTimer);
document.addEventListener("keypress", resetTimer);
startTimer();
}
data() {
return { account: storageLocal.account };
}
}
const component = new HeaderComponent('component-header')
loader.components.set(component.tag, component);
})(window, window.config, window.loader, window.application);
Please note:
signOut() {
storageLocal.delete('account');
window.location = '/signin.html';
}
timer() {
//document.getElementById("timer"),
var counter = -1;
var timeout;
var startTimer = function timer() {
as you can see 'signOut()' is 2 levels below active functions. The logic says it would work like this.parent.signOut() but it DOES NOT !
EDIT3: this.signOut(); will produce
Uncaught TypeError: Cannot read property 'signOut' of undefined
at timer (header.js:30)
at HTMLDocument.resetTimer
The function creates a new context. You need to switch to arrow function and use this.signOut(). Simplified example:
timer() {
var counter = -1;
var timeout;
var startTimer = () => {
counter++;
console.log(counter);
this.signOut();
timeout = setTimeout(startTimer, 1000);
};
setTimeout(startTimer, 1000);
}
Moreover, you have two signOut() methods defined in one class.
You need this and call it like this.signOut()
The startTimer-function does not run in the context of the HeaderComponent's instance.
this in startTimer will point to window when it's executed as a handler in setTimeout.
In order to access the the instance of HeaderComponent, either use an arrow function (as pointed out in an earlier answer. See also Arrow function expressions) which will point this to the outer context (which is HeaderComponent's instance) or define an identifier in timer which points to the instance (eg. const self = this;) and use self instead of this in startTimer.
To apply this to your example (for the sake of consistency, I used var instead of const):
timer() {
var counter = -1;
var timeout;
var self = this;
var startTimer = function() { // Don't use a named function here, it only leads to more confusion
counter++;
console.log(counter);
self.signOut(); // Use `this` of the outer context
timeout = setTimeout(startTimer, 10000); // Use the declared identifier
};
// Rest of the method
}
this is Javascript may be a bit confusing to those who come from different programming languages. If you want to get into more detail, I recommend reading into the MDN reference for this and into Closures

Small issue clearing an interval

I have a small issue clearing an interval with Javascript.
I've searched for the mistake that I've made but I couldn't find any.
Variable declarations:
let i, interval;
let currentLoops = 0;
let settings = {
amount:0,
loops:0,
speed:0};
Where i make my interval:
$('#start').click(()=>{
getSettings();
let interval = setInterval(setColorGrid, settings.speed);
});
How i tried to clear it:
if(currentLoops == settings.loops){
clearInterval(interval);
console.log("interval cleared");
}
If you have any ideas/suggestions for this comment below.
Remove the let part from the event handler. It causes to create a handler function scoped interval variable which shadows the outer interval variable.
$('#start').click(() => {
getSettings();
interval = setInterval(setColorGrid, settings.speed);
});

Using clearInterval within a function to clear a setInterval on another function

I think im missing something fairly obvious with how the clearInterval method works.
So with the code below. I would expect the first function call to execute testFunction and set the interval to repeat the function. The 2nd call would execute the second function which will remove the interval from the 1st function. As this would execute far before the 5000ms interval the first function would not be executed again. However it does not behave like this.
Could someone please explain what is wrong with my method?
Reason for this is in a program I am writing I am making repeated get requests, every 30 seconds or so , using setTimeout but i would like a method to easily remove this interval at other points in the program
function testFunction() {
$("#test").append("test");
setTimeout(testFunction, 5000);
}
function stopFunction() {
clearTimeout(testFunction);
}
testFunction();
stopFunction();
setTimeout returns an ID so you should
var timeoutID = setTimeout(blah blah);
clearTimeout(timeoutID);
setTimeout returns an object that you need to pass into the clearTimeout method. See this article for an example: http://www.w3schools.com/jsref/met_win_cleartimeout.asp
setTimeout returns an identifier for the timer. Store this in a variable like:
var timeout;
function testFunction(){
...
timeout = setTimeout(testFunction, 5000);
}
function stopFunction(){
clearTimeout(timeout);
}
Here is a simple and I think better implementation for this .
var _timer = null,
_interval = 5000,
inProgress = false,
failures = 0,
MAX_FAILURES = 3;
function _update() {
// do request here, call _onResolve if no errors , and _onReject if errors
}
function _start() {
inProgress = true;
_update();
_timer = setInterval(_update, _interval);
}
function _end() {
inProgress = false;
clearInterval(_timer);
}
function _onReject(err) {
if (failures >= MAX_FAILURES) {
_end();
return false;
}
_end();
failures++;
_start();
}
function _onResolve(response) {
return true;
}

Categories

Resources