为什么对于某些帧requestAnimationFrame会被多次调用,而对于其他帧则不会被调用?

4
我有一个redux应用程序,它使用requestAnimationFrame在每个TICK上呈现新状态,然而,Google Chrome似乎会为某些ticks调用requestAnimationFrame多达3次(!!) ,而对于其他一些ticks则根本没有调用,导致动画效果不流畅。
在React开发模式下: Chrome performance timeline screenshot 1 在React NODE_ENV=production模式下: Chrome performance timeline screenshot 2 已经以60fps的速度进行渲染,因此每16ms帧中多余的多个requestAnimationFrame回调对CPU资源极为浪费。 没有tick的帧也会导致动画效果不流畅。 我的tick函数只需要4ms就可以计算出(远低于16ms的预算),且页面上只有一个回调在运行。
以下是处理在每个tick上分派我的redux调用的动画代码。
class AnimationHandler {
    constructor(store) {
        this.store = store
        this.animating = false
        store.subscribe(::this.handleStateChange)
    }
    handleStateChange() {
        if (!this.animating) {
            this.tick()
        }
    }
    tick(timestamp) {
        this.animating = true
        this.store.dispatch({
            type: 'TICK',
            current_timestamp: (new Date).getTime(),
            // reducer handles updating rendered state to this point in time
        })
        window.requestAnimationFrame(::this.tick)
    }
}

window.animations = new AnimationHandler(window.store)  // redux store

什么原因会导致Chrome这样做,如何使每个渲染帧只有一个一致的tick()调用,不多也不少?

1
有相同的问题!你是否找到了答案? - treeseal7
1
当我开始使用NODE_ENV=production环境变量来编译React的生产模式时,情况有所改善。不幸的是,我从未找到根本原因。 - Nick Sweeting
1个回答

0

我曾经遇到过同样的问题。后来发现是我的代码有 bug,我猜想这种情况通常都是如此。

在你的代码中,调用 tick() 会安排一个 requestAnimationFrame 的无限循环,因为 requestAnimationFrame() 总是作为 tick() 的一部分被调用。这是正常的。

如果只在循环外部调用 tick() 一次,那么就不会有问题。虽然在你的示例中没有出现这种情况,但在实际应用中可能会启动多个循环。

以防万一,我建议你将代码改为:

handleStateChange() {
        if (!this.animating) {
            this.animating = true // immediate
            this.tick()
        }
    }

在我的情况下,我正在重用tick()方法,并添加了requestAnimationFrame()的层级。
例如:(错误!)
// init
window.requestAnimationFrame(tick)

// on some other events
tick() // WRONG! will create a new layer of requestAnimationFrame loop!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接