【问题标题】:React Native Rendering with SetInterval Issue使用 SetInterval 问题反应本机渲染
【发布时间】:2019-02-16 12:30:28
【问题描述】:

我刚刚偶然发现我的应用存在性能问题。我正在尝试使用setInterval() 函数制作一个游戏循环,并使用this.forceUpdate() 不断地重新渲染我的游戏。我也尝试过使用this.setState() 重新渲染,但它们都感觉相同。现在,在我的游戏循环中,我不断更新蓝色方块(视图)的 y 位置。它会移动,但有点迟钝。

我将setInterval() 函数的间隔设置为 1000/60 以模拟 60FPS,但在我的应用程序中,感觉就像 20。我也尝试将间隔设置为 1,它很流畅,但它会卡顿很多。我得到了非常迷失方向的微小滞后尖峰。

我认为 this.forceUpdate()this.setState() 不适合我的场景。

还有其他方法可以提高性能吗?

更新:我也使用了requestAnimationFrame() 函数,但它在重新渲染时仍然卡顿。 this.forceUpdate()this.setState() 有替代品吗?我将如何延迟 requestAnimationFrame() 循环,使其以 60FPS 的速度关闭?

感谢阅读,希望我们能找到解决办法。

【问题讨论】:

  • 这就是 requestAnimationFrame 的用途。见facebook.github.io/react-native/docs/timers
  • @estus 我忘了提,我也用过 requestAnimationFrame,它更流畅,但还是有点卡顿。有没有办法可以延迟 requestAnimateFrame 循环,使其仅更新到 60 FPS?
  • 我会避免同时使用 setInterval,因为如果之前的迭代没有在 1000/60 内完成,您将面临产生多个游戏循环迭代的风险
  • 我认为是你的渲染功能造成的。太重了。

标签: javascript reactjs performance loops react-native


【解决方案1】:

如果您坚持认为requestAnimationFrame 不适合您的应用/游戏循环,我建议使用setTimeout 而不是setInterval。原因是,如果循环迭代的执行时间超过 16ms (1000/60),那么您将获得迭代重叠 - 即使先前的迭代尚未完成,也会开始另一个迭代。随着时间的推移,这将导致真正的问题,并可能成为口吃的原因。

作为替代方案,请尝试以下(伪代码):

doLoopIteration = () => {

    this.setState({ /* your mutation */ }, 
    () => { // This callback is fired after a component render caused by setState

        // Sechule next loop iteration in ~16ms. This approach protects
        // against the overlap issue mentioned above
        setTimeout(() => this.doLoopIteration(), 1000 / 60);
    })        
}

// Start the iteration
doLoopIteration()

有关 setState 回调的更多信息,see this documentation。另外,请参阅this documentation for details 关于基于setInterval 的循环敏感的重叠问题。希望对您有所帮助!

【讨论】:

  • 嘿,感谢您的建议,当我有机会时,我会尝试您的替代方案,并且一定会向您更新正在发生的事情。谢谢!
  • @ColeMangio 嘿,不客气 - 是的,让我知道你的进展和/或如果你需要更多帮助 :-)
  • 嘿,我已经成功地实现了你的确切代码,但它的性能仍然不是很好,但是 setTimeout 可以延迟我的循环!因此,我设法做出了一种“弗兰肯斯坦”的想法,即强制调用 componentDidUpdate 函数的更新,将 setTimeout 添加到 requestAnimationFrame 回到循环中。因此,它的性能要好得多。口吃少了。所以我感谢你建议 setTimeout 函数。还。我不确定是否有,但是否有某种其他方式重新呈现应用程序?
  • 嗨@ColeMangio,我的理解是setState()forceState() 是唯一可用于触发当前组件重新渲染的方法。您尝试渲染的组件有多复杂?也许您可以简化它以加快渲染速度?或许你可以研究一下github.com/FormidableLabs/react-game-kit,看看在那个 react 游戏库中游戏循环是如何优化的
  • 嘿!是的,我实际上已经设法真正研究了游戏引擎。 react-native-game-engine 和 react-game-kit 我看过他们的游戏循环,他们使用 requestAnimationFrame();功能和订阅者?对于订阅者数组中的每个订阅者,它会调用一个回调吗?就像字面上调用 callback.call();我不太确定订阅者到底是什么...
【解决方案2】:

如果有人想知道,你真的不应该在 react-native 的状态下编写游戏代码。相反,在 react-native 之外编写你的游戏代码。例如,react-native-canvas 可以在没有状态的情况下以图形方式绘制事物!

【讨论】:

    【解决方案3】:

    好的,我想我已经设法根据你们的建议制作了一个科学怪人代码。 在这里。

      componentDidUpdate() {
        setTimeout(() => {
          requestAnimationFrame(this.loop);
        }, 1000/60);
      }
    
      loop = () => {
        this.forceUpdate();
      }
    

    我注意到性能实际上比我尝试过的所有其他方法都要好。我认为 setInterval/forceUpdate 太重了。是否有另一种重新渲染我的应用程序/游戏的方法?也许绕过重新渲染功能?

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2021-04-14
      • 1970-01-01
      • 2021-06-02
      • 2016-07-13
      • 2021-04-13
      相关资源
      最近更新 更多