Reputation: 596
I have a class that acts as a client to a server (through a WebSocket). I would like to implement a system that periodically pings the server to determine latency. However, I am concerned that if I use setInterval
inside the class for this purpose, it will continue to try to ping after the object should be garbage collected. How can I know when to call clearInterval
?
Summary of code:
class WSClient extends EventEmitter
{
private latency: number;
public get Latency(): number
{ return this.latency; }
public async ping(): Promise<number>
{ ... }
public constructor(options)
{
super();
// Do constructor stuff
setInterval(() => this.ping().then(latency => this.latency = latency), 1000);
}
}
Upvotes: 2
Views: 620
Reputation: 6898
Here's the thing: you'll never reach a point where the object "should" be garbage collected, because the setInterval
you've defined is holding a reference to that object (in your context, as this
) in perpetuity. You're going to need some extra logic to determine if you still need to run it.
What I'd recommend, and it's an easy approach since you've already defined your get Latency()
, is to put some logic in there to monitor if anyone's actually asked for the latency in a while. If the getter's been run recently, keep polling. If it hasn't, remove the interval.
You could make this much easier if you defined, instead, async getLatency()
, that way if you detect that the latency hasn't been recently pinged, you can wait until the latency is recalculated.
I haven't run this, but am including it to illustrate the idea:
// ms to wait until cancelling the interval
const latencyTimeout = 200000;
// In your class
async getLatency(): number {
if (!this.latency) {
const started = Date.now();
const poller = setInterval(async () => {
if (Date.now() - started > latencyTimeout) {
clearInterval(poller);
this.latency = null;
}
this.latency = await this.ping();
}, 1000);
this.latency = await this.ping();
}
return this.latency;
}
As an aside, you may want to consider not using the setInterval
, but a recurring setTimeout
instead. The problem with the interval, is that it's based on its own clock. It won't take into account the amount of time needed to complete the ping. eg if you're polling every second, but it takes 500ms to complete the ping, it'll be okay, but if it takes 2000ms to ping then your pings will actually go out of order. It could look like you have a much slower ping, because you're receiving the return from a ping that took longer than a recent one that ran fast. Better to do a setTimeout
instead that only runs after the last one completed.
Upvotes: 2
Reputation: 861
You can use setInterval() and save it to an variable, then you can access that interval like so:
class WSClient extends EventEmitter
{
private latency: number;
public get Latency(): number
{ return this.latency; }
public async ping(): Promise<number>
{ ... }
public constructor(options)
{
super();
// Do constructor stuff
this.interval = setInterval(() => this.ping()
.then(latency => this.latency = latency), 1000);
}
}
Then when you need:
WSClient.interval.clearInterval();
Upvotes: 2