角组件与requestAnimationFrame问题 [英] Angular component with requestAnimationFrame issue

查看:89
本文介绍了角组件与requestAnimationFrame问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

im与Angular 9一起使用THREE.Js.该应用程序允许您通过单击按钮在2D html组件和3D ThreeJs组件之间切换.3D组件在 ngAfterViewInit 上创建threejs所需的所有内容,并使用 requestAnimationFrame 调用循环函数.

im using Angular 9 together with THREE.Js. The app lets you switch between a 2D html component and a 3D ThreeJs component via button click. The 3D component creates all needed for threejs on ngAfterViewInit and calls a loop function with requestAnimationFrame.

  private loop() {

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

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

一旦加载了场景的所有模型并触发了onLoad回调,或者触发了 ngOnDestroy 时,循环就被取消.

The loop gets canceled as soon as all models of my scene are loaded and the onLoad callback is fired or when ngOnDestroy is fired.

  private stopLoop() {

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

当不时切换组件时,此方法效果很好,但是当更快或连续几次单击按钮时,requestAnimationFrame不会停止并累加.我使用stats-js lib来检测帧速率,通常约为40fps,但总和可达120-220fps或更高.我的电脑开始停滞并且无法工作,一切都变慢了.

This works fine when switching components from time to time, but when clicking the button faster or several times in a row, the requestAnimationFrame won't stop and adds up. Im using the stats-js lib to detect frame rate, normally its around 40fps, but it adds up to 120-220fps or more. My computer starts to lag and work and everything slows down.

通常它应该为0,因为加载完所有内容后,就不再应该有animationframe了!

Normally it should be at 0 because when everything is loaded, there should be no animationframe anymore!

如何避免这种行为?

更新:好像我发现了问题.我的错误是 bind 循环函数,该函数每次都会生成一个新实例.我对此感到怀疑,因为AFID仍在更新,因此取消了animationFrame.但是不绑定会给我到处乱七八糟的未定义属性的错误

Update: Seems like I found the issue. My mistake was to bind the loop function, which generates a new instance everytime. Tho I have doubts because the AFID is still getting updated and therefore canceles the animationFrame. But to not bind gives me some errors of undefined properties here and there

由于棱角分明,Kinda很难对所有这些内容进行修饰

Kinda hard to jsfiddle all of that, because of the angular part

推荐答案

removeEventListener 不同, cancelAnimationFrame 根本不关心已计划的功能,因此您的绑定事情无关.

Unlike removeEventListener, cancelAnimationFrame doesn't care at all what function has been scheduled, so your binding thing is unrelated.

问题必须是您多次调用此 loop()方法,因此有多个这样的循环同时运行.

The problem must be that you call multiple times this loop() method, and thus have several such loop running concurrently.

因此,请尝试查找不应该调用的内容.

现在,一种避免这种情况的快速方法是,在输入以下 loop()方法时取消所有待处理的动画帧回调:

Now, one quick way to avoid this situation is to cancel any pending animation frame callback when entering this loop() method:

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

<label>Cancel pending frames at beginning<input type="checkbox" id="check"></label><br>
<button id="start_btn">instance.loop()</button><br>
<button id="stop_btn">instance.stop()</button><br>
<pre id="log"></pre>
<script>
  var logger = document.getElementById('log');
  let last_time;
  let iterations;
  function countCallsPerFrame( time ) {
    if( last_time !== time ) {
      last_time = time;
      iterations = 1;
    }
    else {
      iterations ++;
    }
    logger.textContent = `
Timestamp: ${ time | 0 }
called ${ iterations } time(s) per frame.`;
  };
</script>

这篇关于角组件与requestAnimationFrame问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆