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.
Related
So I have a postActions.js in my code where I write all my Redux action codes.
One of the functions in it is a logout code.
This is the code.
export const logout = () => {
localStorage.removeItem('token');
localStorage.removeItem('expirationDate');
return {
type: AUTH_LOGOUT
}
}
This logout action creator is called after an expiration time has reached. This is done using a setTimeout function like below.
export const checkAuthTimeout = expirationTime => {
return dispatch => {
timeoutVar = setTimeout(() => {
dispatch(logout());
}, expirationTime*1000);
}
}
timeoutVar is declared in the top of the code, outside all the functions like this.
var timeoutVar;
Now here is my problem. Whenever a person is active in the app, I want to change setTimeout to a later time, so that he is not logged out when he is active. This is done with a code like this. logoutTime is the new time to be used for setTimeout.
clearTimeout(timeoutVar);
dispatch(checkAuthTimeout(logoutTime));
For some reason, the above code is not changing setTimeout. Lets say logoutTime is 10, it is supposed to change setTimeout to happen 10 more seconds from now, but it does not change anything.
If I only use clearTimeout(timeoutVar), the timer stops.
That is working. But when I also use dispatch(checkAuthTimeout(logoutTime)) the event happens at the old time itself. I am stuck with this for a long time. Please help.
I found the answer. Finally.
Since its React, my components were getting called multiple times and this triggered the setTimeout function multiple times. So there were multiple instances of setTimeout running. I had setTimeout called outside the function call like this -
clearTimeout(timeoutVar);
dispatch(checkAuthTimeout(logoutTime));
But checkAuthTimeout was also getting called in other locations without clearTimeout due to some lifecycle methods without clearTimeout and this created many instances of setTimeout. Safest option is to move clearTimeout inside the function. Like this.
export const checkAuthTimeout = expirationTime => {
return dispatch => {
clearTimeout(timeoutVar); // ADD THIS JUST BEFORE SETTIMEOUT
timeoutVar = setTimeout(() => {
dispatch(logout());
}, expirationTime*1000);
}
}
I just had to add a clearTimeout just before setTimeout all the time.
<input autocomplete="off" [config]="config2" [items]="items2" (inputChangedEvent)="onInputChangedEvent($event)" (selectEvent)="onSelect($event)">`enter code here`
onInputChangedEvent(val: string) {
this.changeEvent.emit(val);
this.inputChanged = val;
if (this.timer) {
clearTimeout(this.timer);
}
// trigger the search action after 400 millis
this.timer = setTimeout(this.searchFunction(val), 200);
}
I am using InputChangedEvent ,how can we delay the event
You can't pass a function with arguments to setTimeout(), you need to create another function where in you call this function:
var _this = this;
setTimeout(function () {
_this.searchFunction(val);
}, 200);
By passing the function directly to setTimeout, JavaScript executes the function and uses the return value as the callback. So your searchFunction is executed every time.
Are you asking how to trigger the action only if there has been no typing for 400msec?
If so, the usual approach is a "deadman's switch" (name borrowed from an old safety device on trains, I believe).
The basic idea is that each time you see a keystroke, you kill the existing timer (if any) and start a timer for 400msec.
Then, if the timer finally triggers, you know that 400msec have passed without a keystroke, and you can do the action.
I'm writing a "Game of Life" in javascript. I have all the logic done in a function called doGeneration(). I can repeatedly call this from the console and everything goes as planned, however, if I put it in a while loop the execution blocks the UI and I just see the end result (eventually).
while (existence) {
doGeneration();
}
If I add a setTimeout(), even with a generation limit of say 15, the browser actually crashes (Canary, Chrome).
while (existence) {
setTimeout(function() {
doGeneration();
},100);
}
How can I call doGeneration() once every second or so without blocking the DOM/UI?
You want setInterval
var intervalId = setInterval(function() {
doGeneration();
}, 1000);
// call this to stop it
clearInterval(intervalId);
I would use requestAnimationFrame(doGeneration). The idea of this function is to let the browser decide at what interval the game logic or animation is executed. This comes with potential benefits.
https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/
Rather than using setINterval or setTimeout and assume some random time interval will be enough for the UI to update you shoul/could make the doGeneration smart enough to call itself after dom was updated and if the condition of existence is satisfied.
I am very new to React JS and in some ways javascript here is the problem I am trying to solve. I have a function in a component that looks like the below that iterates through an array of numbers:
playerSequence: function() {
var game = this;
this.state.game.sequence.map(function(currNum){
console.log(currNum);
switch(currNum){
case 1:
game.handleBlue();
break;
case 2:
game.handleYellow();
break;
case 3:
game.handleGreen();
break;
case 4:
game.handleRed();
break;
}
})
},
Each function call has a setTimeout that waits a period of time and renders a light and then switches off the light after this.props.wait ms. Below is an example:
var RedOn = React.createClass({
mixins: [TimerMixin],
componentDidMount: function () {
this.setTimeout(function(){this.props.handleRed()}, this.props.wait);
},
handleRed: function() {
this.props.handleRed()
},
renderstuff
});
What I would like is for each pass through the map array to wait until the function call is finished and then continue. As it is right now they all go off at the same time. I am sure I am not fully understanding the nature of node, react or a combo of both. Any help would be appreciated.
According to the React docs, componentDidMount is Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.
So it would make sense that they would all fire at once. The other problem is that setTimeout is invoked as soon as its called, which means if you pass some time in milliseconds to each function, map will simply invoke them all at once, not apply them sequentially. If you wanted to keep using map, you should declare a variable to store previous time applied, and add it into each timeout.
var previousTime = 0;
["foo", "bar", "baz"].map( function(e) {
setTimeout( function() { console.log(e); }, 1000 + previousTime);
previousTime += 1000; });
Here's a trivial example of what I'm describing. Try running this in a console to see the result. Every time you call "setTimeout" you add the time to the previousTime variable, so that each element waits an additional second before showing.
At the end of the day, even with all the abstractions offered by React, remember It'sJustJavaScriptâ„¢
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".