БлогNot. Javascript: как запустить код по таймеру из метода класса

Javascript: как запустить код по таймеру из метода класса

Представим, что хотим запускать функцию класса Javascript по таймеру с помощью setTimeout или setInterval.

Увы, казалось бы, естественное

this.timerId = setTimeout(function () { this.doTimer (); }, this.timeInterval);

написанное в другом методе класса, к успеху не приведёт, лишь будем получать с периодом таймера ошибку

Uncaught TypeError: this.doTimer is not a function

Такие вещи способны свести с ума, если не знать, что помогает простое "клонирование" this:

let that = this;  //Без такого клонирования ссылки не работает setTimeout из класса
this.timerId = setTimeout(function () { that.doTimer (); }, this.timeInterval);

Ссылки на свойства, такие как this.timeInterval, можно оставить без изменений.

Обратите внимание, что приведённый ниже код (документ HTML без обрамления, кодировка Юникода UTF-8) ровно 100 шагов делать отнюдь не обязан, с измерениями малых интервалов времени у JS тоже бывают проблемы. К тому же, когда вкладка перестаёт быть активной, современные браузеры практически перестают выполнять в ней код, вызываемый по таймеру.

<div id="counter"></div>
<script>
 class Class {
  constructor (id, steps, ms) { //id элемента, количество шагов, время шага в мс
   this.id = id;
   this.elem = document.getElementById (id);
   if (!this.elem) {
    console.error ('Class: Item with id='+id+' not found');
   }
   let Steps = parseInt (steps);
   if (isNaN(Steps) || Steps < 1) {
    console.error ('Class: steps is not a positive number'); 
   }
   let Ms = parseInt (ms);
   if (isNaN(Ms) || Ms < 1) {
    console.error ('Class: ms is not a positive number'); 
   }
   let dt = new Date();
   this.startTime = dt.getTime();
   this.endTime = this.startTime + Steps*Ms;
   this.timeInterval = Ms;
   this.cnt = 0;
  }
  run () {
   this.doTimer ();
  }
  doTimer () {
   let dt = new Date();
   let currentTime = dt.getTime();
   if (currentTime < this.endTime) {
    this.cnt++;
    this.elem.innerHTML = this.cnt;
    let that = this;  //Без такого клонирования ссылки не работает setTimeout из класса
    this.timerId = setTimeout(function () { that.doTimer (); }, this.timeInterval);
   }
   else {
    clearInterval(this.timerId);
   }
  }
 }

 let timer = new Class ('counter', 100, 100);
 timer.run();
</script>
<noscript><p>Нужен Javascript для работы приложения!</p></noscript>

теги: ошибка javascript памятка время

10.02.2021, 19:19; рейтинг: 42