How cancel Timeout inside object - javascript

I have the following code:
const timers = []
const timer1 = setTimeout(() => {
console.log('Starting timer2')
const timer2 = setTimeout(() => {
console.log('Its works')
}, 10000)
timers.push({key:2, id:timer2})
}, 10000);
timers.push({key:1, id:timer1})
function remove(key) {
for (i = 0; i > timers.length; i++) {
if (timers[i].key === key) {
timers = timers.slice(i, 1)
clearTimeout(timers[i].id)
}
}
}
When I call the remove(key) function the code is not removing the timers as expected

const timers = []
const timer1 = setTimeout(() => {
console.log('Starting timer2')
const timer2 = setTimeout(() => {
console.log('Its works')
}, 10000)
timers.push({key:2, id:timer2})
}, 10000);
timers.push({key:1, id:timer1})
function remove(key) {
const timer = timers.find(f => f.key === key);
if (timer) {
clearTimeout(timer.id);
}
}

Related

How to turn off the websocket after component unmounts

this is my code snippet bellow,
I am trying to close the websocket connection after component unmounts, I just totally dont know how to do it
I am using this useEffect inside the same component I am also using useref to count the mounted count of the component so that the websocket doesn't creates more that 1 instance at a time
const mountedCount = useRef(0);
useEffect(() => {
const handleWebsocket = () => {
mountedCount.current++;
const socketURL = 'socket url here'
const socket = new WebSocket(socketURL);
socket.onopen = () => {
console.log('socket open')
};
socket.onclose = (closeEvent) => {
if (closeEvent.wasClean) return;
timeout = setTimeout(() => {
handleWebsocket();
}, envVariables.webSocketReconnectionTimeout);
};
socket.onerror = () => {
console.log('error here')
};
socket.onmessage = (messageEvent) => {
console.log('got the message')
};
return socket;
};
if (mountedCount.current === 0) {
handleWebsocket();
}
return () => {
clearTimeout(timeout);
};
}, [
dispatch,
userData.userInformation,
wss.connectionStatus
]);
const mountedCount = useRef(0);
const [currentSocket,setCurrentSocket]=useState(null)
useEffect(() => {
const handleWebsocket = () => {
mountedCount.current++;
const socketURL = 'socket url here'
const socket = new WebSocket(socketURL);
socket.onopen = () => {
console.log('socket open')
};
socket.onclose = (closeEvent) => {
if (closeEvent.wasClean) return;
timeout = setTimeout(() => {
handleWebsocket();
}, envVariables.webSocketReconnectionTimeout);
};
socket.onerror = () => {
console.log('error here')
};
socket.onmessage = (messageEvent) => {
console.log('got the message')
};
return socket;
};
if (mountedCount.current === 0) {
setCurrentSocket(handleWebsocket());
}
return () => {
clearTimeout(timeout);
currentSocket?.close();
};
}, [
dispatch,
userData.userInformation,
wss.connectionStatus
]);
or you can declare socket variable in one upper scope:
const mountedCount = useRef(0);
useEffect(() => {
let socket
const handleWebsocket = () => {
mountedCount.current++;
const socketURL = 'socket url here'
socket = new WebSocket(socketURL);
socket.onopen = () => {
console.log('socket open')
};
socket.onclose = (closeEvent) => {
if (closeEvent.wasClean) return;
timeout = setTimeout(() => {
handleWebsocket();
}, envVariables.webSocketReconnectionTimeout);
};
socket.onerror = () => {
console.log('error here')
};
socket.onmessage = (messageEvent) => {
console.log('got the message')
};
return socket;
};
if (mountedCount.current === 0) {
handleWebsocket();
}
return () => {
clearTimeout(timeout);
socket.close()
};
}, [
dispatch,
userData.userInformation,
wss.connectionStatus
]);

How to properly extend the Promise class?

I have a custom Promise2 class that extends Promise class to allow early settling. It uses my custom Timer class to check the progress of a simulated activity through another timer t1. In my example, p1 does an early settling but the problem is with the p1.then( doesn't recognize the onfulfilled callback as a function.
I suspected I have to override then() and call the super.then() but it didn't work. By the way, the timed executor callback inside super() is just a workaround to make this accessible. Any ideas on what's lacking in my Promise2 class?
JavaScript Code
'use strict';
const p1 = new Promise2(
(resolve, reject) => {
const t1 = Timer.create(
() => {
resolve('Promise resolved.');
// reject(new Error('Promise rejected.'));
},
3000,
);
return { timer: t1 };
},
);
Timer.create(
() => {
const { isCompleted } = p1.return.timer;
const { progress } = p1.return.timer;
if (isCompleted === false) {
console.log(`Promise: ${progress} %`);
if (progress > 50) {
p1.resolve('Early resolve.');
// p1.reject(new Error('Early reject.'));
p1.return.timer.stop();
}
}
},
250,
true,
16,
);
// p1.promise.then(
p1.then(
(value) => {
console.log('__resolve__');
console.log(value);
},
)
.catch(
(reason) => {
console.log('__catch__');
console.log(reason);
},
);
Promise2 Class
class Promise2 extends Promise {
constructor(executor = null) {
super(
(resolve, reject) => {
Timer.create(
() => {
this.resolve = resolve;
this.reject = reject;
this.return = executor(resolve, reject);
},
1);
},
);
// this.promise = new Promise(
// (resolve, reject) => {
// this.resolve = resolve;
// this.reject = reject;
// this.return = executor(resolve, reject);
// },
// );
}
static create(executor = null) {
return new Promise2(...arguments);
}
}
Timer Class
class Timer {
constructor(workload = null, milliseconds = 1000, isAutostart = true, repeat = 1, isInterval = false) {
this.workload = workload;
this.milliseconds = milliseconds;
this.isAutostart = isAutostart;
this.repeat = repeat;
this.isInterval = isInterval;
this.startTime = 0;
this.endTime = 0;
this.timeLeft = milliseconds;
this.timeoutId = 0;
this.progress = 0;
this.isCompleted = false;
this.endTimeActual = 0;
this.repeatLeft = repeat;
this.isPaused = false;
this.subTimers = [];
if (isAutostart === true) {
this.start();
}
}
start(thisArg = this) {
thisArg.startTime = Date.now();
thisArg.endTime = thisArg.startTime + thisArg.milliseconds;
const timeoutEndTime = Date.now();
thisArg.watch(thisArg.workload, timeoutEndTime, thisArg);
}
watch(workload = null, timeoutEndTime = 0, thisArg = this) {
if (thisArg.isPaused === true) {
return;
}
const timeoutLag = Date.now() - timeoutEndTime;
thisArg.timeLeft = thisArg.endTime - Date.now() - timeoutLag;
if (thisArg.timeLeft > 0) {
thisArg.progress = 100 - ((thisArg.timeLeft / thisArg.milliseconds) * 100);
const inProgress = 100 - thisArg.progress;
const tick = thisArg.timeLeft / inProgress;
timeoutEndTime = Date.now() + tick;
thisArg.timeoutId = setTimeout(thisArg.watch, tick, thisArg.workload, timeoutEndTime, thisArg);
return;
}
thisArg.stop(thisArg);
workload();
if (thisArg.repeatLeft > 0) {
thisArg.isCompleted = false;
thisArg.start();
}
if (thisArg.isInterval === true) {
thisArg.repeatLeft = 1;
}
if (thisArg.subTimers.length > 0) {
thisArg.subTimers.forEach(
(timer) => {
if (timer.isAutostart === true) {
timer.start();
}
},
);
}
}
stop(thisArg = this) {
clearTimeout(thisArg.timeoutId);
thisArg.isCompleted = true;
thisArg.endTimeActual = Date.now();
thisArg.repeatLeft -= 1;
if (thisArg.isInterval === true) {
thisArg.repeatLeft = 0;
}
}
restart(thisArg = this) {
thisArg.stop();
thisArg.startTime = 0;
thisArg.endTime = 0;
thisArg.timeLeft = thisArg.milliseconds;
thisArg.timeoutId = 0;
thisArg.progress = 0;
thisArg.isCompleted = false;
thisArg.endTimeActual = 0;
thisArg.repeatLeft = thisArg.repeat;
thisArg.start();
}
pause(thisArg = this) {
thisArg.isPaused = true;
}
resume(thisArg = this) {
thisArg.isPaused = false;
const timeoutEndTime = Date.now();
thisArg.watch(thisArg.workload, timeoutEndTime, thisArg);
}
static create(workload = null, milliseconds = 1000, isAutostart = true, repeat = 1, isInterval = false) {
return new Timer(...arguments);
}
static chain(timers = []) {
const timerReferences = Timer.chainWalk(timers);
if (timerReferences[0].isAutostart === true) {
timerReferences[0].start();
}
return timerReferences;
}
static chainWalk(timers = [], timerReferences = [], nextTimer = null) {
if (timers.length === 0) {
return timerReferences;
}
if (timerReferences.length === 0) {
timers = [...timers];
}
const timer = timers.shift();
const {
workload = null,
milliseconds = 1000,
isAutostart = true,
repeat = 1,
isInterval = false,
} = timer;
const newTimer = new Timer(workload, milliseconds, false, repeat, isInterval);
newTimer.isAutostart = isAutostart;
if (timerReferences.length === 0) {
timerReferences.push(newTimer);
[nextTimer] = timerReferences;
} else {
nextTimer.subTimers.push(newTimer);
[nextTimer] = nextTimer.subTimers;
}
timerReferences = Timer.chainWalk(timers, timerReferences, nextTimer);
return timerReferences;
}
static tree(timers = []) {
const timerReferences = Timer.treeWalk(timers);
timerReferences.forEach(
(reference) => {
if (reference.isAutostart === true) {
reference.start();
}
},
);
return timerReferences;
}
static treeWalk(timers = []) {
const timerReferences = [];
timers.forEach(
(timer) => {
const {
workload = null,
milliseconds = 1000,
isAutostart = true,
repeat = 1,
isInterval = false,
subTimers = [],
} = timer;
const newTimer = new Timer(workload, milliseconds, false, repeat, isInterval);
newTimer.isAutostart = isAutostart;
if (Array.isArray(subTimers) === true) {
newTimer.subTimers = Timer.treeWalk(subTimers);
}
timerReferences.push(newTimer);
},
);
return timerReferences;
}
}
Console Output
Promise2 Class (Working Alternative)
class Promise2 {
constructor(executor = null) {
this.promise = new Promise(
(resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
this.return = executor(resolve, reject);
},
);
this.then = function (onfulfilled = null, onrejected = null) {
return this.promise.then(...arguments);
};
this.catch = function (onrejected = null) {
return this.promise.catch(...arguments);
};
this.finally = function (onfinally = null) {
return this.promise.finally(...arguments);
};
}
static create(executor = null) {
return new Promise2(...arguments);
}
}

Why this setInterval is executing multiple times?

I have the below code in a vue application
mounted: function () {
this.timer = setInterval(async () => {
if (this.progress >= 1) {
this.progress = 1
clearInterval(this.timer)
}
console.log('update')
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const response = progOut.data
this.progress = response.data.progress / 100
this.state = response.data.status
}, 7000)
},
I was expecting it to execute the get request every 7 seconds but it is executing the call every 500ms approx
I read other answers and so far I think this is the proper way but the code is executing too many requests
What is the proper way to call a function from within the setInterval to make it actually wait the timeout?
Edit: This was my final code in case someone goes through the same
methods: {
redirect (page) {
if (page === 'FINISHED') {
this.$router.push({
name: 'viewReport',
params: { id: 4 }
})
} else {
this.$router.push({
name: 'errorOnReport',
params: { id: 13 }
})
}
}
},
watch: {
state: async function (newVal, old) {
console.log('old ' + old + ' newVal ' + newVal)
if (newVal === 'FAILED' || newVal === 'FINISHED') {
this.redirect(newVal)
}
}
},
data () {
return {
state: null,
timer: null,
progress: 0.0,
progressStr: '0%'
}
},
mounted () {
const update = async () => {
if (this.progress >= 1) {
this.progress = 1
}
console.log('update ' + new Date())
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const response = progOut.data
this.state = response.data.status
this.progress = response.data.progress / 100
this.progressStr = response.data.progress + '%'
}
update()
this.timer = setInterval(update, 10000)
},
beforeUnmount () {
clearInterval(this.timer)
}
A better design is to wrap setTimeout with a promise, and do the polling in an async method that loops...
mounted: function() {
this.continuePolling = true; // suggestion: we have to stop sometime. consider adding continuePolling to data
this.poll();
},
unmounted: function() { // almost the latest possible stop
this.continuePolling = false;
},
methods:
async poll(interval) {
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
while(this.continuePolling) {
await this.updateProgress();
await delay(7000);
}
},
async updateProgress() {
const id = this.$route.params.id
const progOut = await this.api.get(`/api/mu/job/${id}/status`)
const result = progOut.data.data;
this.progress = result.progress / 100
this.state = result.status
}

Increase and Decrease the values

I have a problem. The values from the data array should be increased or decreased every 5 seconds with 0.0001 by following the rule: values should go up for the first minute, then down for the next minute, and so on -
const data = [
{ AUD: "1.5876" }, { BGN: "1.9558" }, { GBP: "0.8527" }, { USD: "1.1820" },
{ UYU: "51.9732" }, { UZS: "12570.5509" }, { VEF: "252746931045.8590" },
{ VND: "27195.9489" }, { VUV: "130.1601" }, { WST: "3.0161" }, { XAG: "0.0449" },
{ XAU: "0.0006" }, { XCD: "3.1944" }, { XDR: "0.8306" },
];
This is my code, but i got an infinity loop.
const [currencies, setCurrencies] = useState([]);
let initialTime = true;
useEffect(() => {
let init = setTimeout(() => {
initialTime = false;
console.log('changing the time ' + initialTime);
}, 5000);
return () => clearTimeout(init)
}, []);
function increase() {
data.forEach(e => {
let value = Number(Object.values(e)[0]);
const key = Object.keys(e)[0];
setCurrencies({ [key]: value += 0.0001 });
})
console.log(currencies);
}
let interval = setInterval(() => {
if (initialTime) {
increase()
} else {
return () => clearInterval(interval);
}
}, 1000);
So keep track of the time and determine how long it has been and when it hits the length of time, flip it.
let updateTime = Date.now();
const endTime = updateTime + 20000;
let dir = 1;
let value = 1.2357;
const flipTime = 5000;
const timer = setInterval(function () {
if(Date.now() - updateTime >= flipTime) {
updateTime = Date.now();
dir *= -1;
}
value += dir * .0001;
console.log(value.toFixed(4));
// If over end time, stop looping
if (Date.now() >= endTime) {
window.clearTimeout(timer);
}
}, 1000);
Side note, setInterval is not 100% accurate so you will see the numbers float around as time runs on.

How to deal with multiple files?

I have two .js-files:
main.js
require("./randomEvent.js").start("hey");
require("./randomEvent.js").start("hi");
require("./randomEvent.js").start("hello");
randomEvent.js
var repeat = true;
exports.start = (randomString) => {
while (repeat) {
console.log(randomString);
}
}
exports.stop = (randomString) => {
repeat = false;
}
I want to start randomEvent.js 3 times, each with different randomStrings.
And if I do
require("./randomEvent.js").stop("hi");
it should stop the start("hi") function / it should set repeat to false.
How?
Thanks in advance!
You can implement your randomEvents.js as a class. So every instance has its own repeat flag.
function RandomEvent(str) {
this.repeat = true;
this.randomString = str;
this.start = () => {
setInterval(() => {
if (this.repeat) {
console.log('-->', this.randomString);
}
}, 1000);
}
this.stop = () => {
this.repeat = false;
}
}
module.exports = RandomEvent;
and main.js
let RandomEvent = require('./randomEvent');
let sayHi = new RandomEvent('hi');
let sayHello = new RandomEvent('hello');
let sayHey = new RandomEvent('hey');
sayHi.start();
sayHello.start();
sayHey.start();
setTimeout(() => {
console.log('stop saying hi')
sayHi.stop();
}, 5000);
Or you can store for every string, its own flag:
randomEvents.js
var repeat = {};
exports.start = (randomString) => {
repeat[randomString] = true;
setInterval(() => {
if (repeat[randomString]) {
console.log('-->', randomString);
}
}, 1000);
}
exports.stop = (randomString) => {
repeat[randomString] = false;
}
and in main.js
require("./randomEvent.js").start("hey");
require("./randomEvent.js").start("hi");
require("./randomEvent.js").start("hello");
setTimeout(() => {
console.log('stop saying hi')
require("./randomEvent.js").stop("hi");
}, 5000);
randomEvent.js
var repeatFlags = {};
function repeatLog(str) {
if (repeatFlags[str]) {
console.log(str);
setTimeout(() => {
repeatLog(str);
});
}
}
exports.start = (randomString) => {
repeatFlags[randomString] = true;
repeatLog(randomString);
}
exports.stop = (randomString) => {
repeatFlags[randomString] = false;
}

Categories