clearInterval, когда на объект больше не ссылаются? - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть класс, который действует как клиент для сервера (через WebSocket). Я хотел бы реализовать систему, которая периодически пингует сервер для определения задержки. Тем не менее, я обеспокоен тем, что если я использую setInterval внутри класса для этой цели, он будет продолжать пытаться пропинговать после того, как объект должен быть собран мусором. Как я могу узнать, когда позвонить clearInterval?

Краткое описание кода:

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);
    }
}

Ответы [ 2 ]

0 голосов
/ 29 апреля 2018

В том-то и дело: вы никогда не достигнете точки, где объект «должен» собираться мусором, потому что определенный вами setInterval содержит ссылку на этот объект (в вашем контексте, как this) навечно. Вам понадобится дополнительная логика, чтобы определить, нужно ли вам ее запускать.

То, что я бы порекомендовал, и это простой подход, поскольку вы уже определили свой get Latency(), - это ввести некоторую логику, чтобы отслеживать, действительно ли кого-то спрашивают о задержке через некоторое время. Если геттер был запущен недавно, продолжайте опрос. Если это не так, удалите интервал.

Вы могли бы сделать это намного проще, если бы вместо этого вы определили async getLatency(). Таким образом, если вы обнаружите, что задержка не была недавно проверена, вы можете подождать, пока задержка не будет пересчитана.

Я не запускал это, но включаю его, чтобы проиллюстрировать идею:

// 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;
}

Кроме того, вы можете рассмотреть возможность не использования setInterval, а периодического setTimeout. Проблема с интервалом в том, что он основан на собственных часах. Он не будет учитывать количество времени, необходимое для завершения пинга. например, если вы опрашиваете каждую секунду, но для пинга требуется 500 мсек, все будет в порядке, но если пинг потребует 2000 мсек, тогда ваши пинги будут фактически не работать. Может показаться, что у вас гораздо более медленный пинг, потому что вы получаете отдачу от пинга, который занял больше времени, чем недавний, который работал быстро. Вместо этого лучше сделать setTimeout, который запускается только после последнего выполненного.

0 голосов
/ 29 апреля 2018

Вы можете использовать setInterval () и сохранить его в переменной, затем вы можете получить доступ к этому интервалу следующим образом:

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);
    }
}

Тогда, когда вам нужно:

WSClient.interval.clearInterval();
...