Angular компонент с проблемой requestAnimationFrame - PullRequest
0 голосов
/ 26 февраля 2020

я использую Angular 9 вместе с ТРИ. Js. Приложение позволяет переключаться между компонентом 2D html и компонентом 3D Three Js нажатием кнопки. 3D компонент создает все необходимое для трех js на ngAfterViewInit и вызывает функцию al oop с requestAnimationFrame.

  private loop() {

    this.AFID = requestAnimationFrame(this.loop.bind(this))

    this.renderer.render(this.scene, this.camera)
  }

l oop отменяется, как только загружаются все модели моей сцены и срабатывает обратный вызов onLoad или когда ngOnDestroy.

  private stopLoop() {

    cancelAnimationFrame(this.AFID)
    this.AFID = null
  }

This отлично работает при переключении компонентов время от времени, но при нажатии кнопки быстрее или несколько раз подряд, requestAnimationFrame не останавливается и складывается. Я использую stats- js lib для определения частоты кадров, обычно она составляет около 40 кадров в секунду, но она добавляет до 120-220 кадров в секунду или более. Мой компьютер начинает зависать и работать, и все замедляется.

enter image description here

Обычно это должно быть в 0, потому что, когда все загружено, не должно быть никакого кадра анимации больше!

Как мне избежать такого поведения?

Обновление: Похоже, я нашел проблему. Моя ошибка была в bind функции l oop, которая генерирует новый экземпляр каждый раз. Хотя у меня есть сомнения, потому что AFID все еще обновляется и поэтому отменяет animationFrame. Но отсутствие привязки дает мне некоторые ошибки неопределенных свойств тут и там

1 Ответ

1 голос
/ 28 февраля 2020

В отличие от removeEventListener, cancelAnimationFrame совершенно не заботится о том, какая функция была запланирована, поэтому ваша привязка не связана.

Проблема должна заключаться в том, что вы несколько раз вызываете этот метод loop(), и, таким образом, несколько таких l oop выполняются одновременно.

Поэтому попробуйте найти то, что вызывает его, когда не следует.

Теперь, один быстрый способ избежать этой ситуации - отменить любой ожидающий обратный вызов кадра анимации при вводе этот loop() метод:

const checkbox = document.getElementById('check');
const start_btn = document.getElementById('start_btn');
const stop_btn = document.getElementById('stop_btn');
const instance = {
  loop(time) {
    if( checkbox.checked ) { // for demo only, you'd always want it
      cancelAnimationFrame( this.AFID ); // revoke any pending operation
    }
    this.AFID = requestAnimationFrame(this.loop.bind(this))

    countCallsPerFrame( time );
  },
  stop() {
    cancelAnimationFrame( this.AFID );
    logger.textContent = '\nstopped';
  }
};

// for demo let's call it three time at startup
for(let i=0; i<3; i++) {
  instance.loop();
}

start_btn.onclick = (evt) => instance.loop();
stop_btn.onclick = (evt) => instance.stop();



var logger = document.getElementById ('log'); пусть last_time; пусть итерации; function countCallsPerFrame (time) {if (last_time! == time) {last_time = time; итерации = 1; } else {iterations ++; } logger.textContent = `Метка времени: $ {time | 0} называется $ {iterations} time (s) per frame`; };
...