请求动画函数开头或结尾的帧
requestAnimationFrame at beginning or end of function?
如果我有一个使用 requestAnimationFrame 的循环,如下所示:
function render() {
// Rendering code
requestAnimationFrame(render);
}
如果我把requestAnimationFrame
放在函数的开头,会有什么区别吗,就像这样:
function render() {
requestAnimationFrame(render);
// Rendering code
}
我没有注意到任何区别,但我看到了这两种实现,其中一个在任何方面都更好,还是它们相同?
编辑:我想过的一件事是,如果我把它放在开头,渲染代码需要相当长的时间才能运行,比如 10 毫秒,最后放进去不会让帧速率下降 10 毫秒吗?
requestAnimationFrame
总是异步调用其回调,因此只要渲染代码是同步的并且不抛出异常,它就不会有任何区别。
这本质上是一种风格选择,选择自己哪种方法更干净。将其放在顶部可能会强调render
正在调度自身,即使在渲染中存在错误的情况下也会这样做。将其放在底部可以有条件地脱离渲染循环(例如,当您想要暂停游戏时)。
它可能不会产生差异。requestAnimationFrame
方法是异步的,因此无论哪种方式,渲染函数都将按预期工作。但。。。在停止方面有一个问题。假设您有以下代码:
function render() {
requestAnimationFrame(render);
// Rendering code
}
为了停止下一次渲染,需要调用 cancelAnimationFrame
方法,如下所示:
function render() {
requestAnimationFrame(render);
// Rendering code
if (noLongerInterested) {
cancelAnimationFrame();
}
}
否则,render
方法将无限期运行。或者,您可以执行以下操作:
function render() {
// Rendering code
if (stillInterested) {
requestAnimationFrame(render);
}
}
至于丢帧,您可以将requestAnimationFrame
视为固定时间表(每秒 60 帧,大约是 16 毫秒的间隔)。如果您的代码花费的时间超过此时间,浏览器将开始丢帧。查看 Patrick Roberts 的回答,了解如何掌控帧,并使用它来实现更一致的渲染。
我希望这有所帮助!
为了回答您的问题,仅当渲染代码长于动画帧速度(通常约为 16 - 33 毫秒,具体取决于浏览器实现)时,这两个函数才会对异步回调发生所需的时间产生影响。但是,如果您按预期使用此 API,即使这样也不应该有什么不同。
请注意,您选择不使用从requestAnimationFrame
传递的可选参数 - timestamp
。
如果要渲染任何与增量时间相关的动画,请确保计算增量。通常,您将动画"速度"乘以timestamp
增量(当前timestamp
减去前timestamp
),以获得物体在屏幕上行进的有效距离。当呈现代码执行每一帧的时间不一致时,其效果尤其明显。
演示
var untimed = 20;
var timed = 20;
function untimedRender() {
var then = performance.now() + Math.random() * 100;
while (performance.now() < then) {}
// estimated velocity
untimed += 50 / 30;
document.querySelector('#untimed').style.left = Math.min(Math.floor(untimed), 200) + 'px';
if (untimed < 200) {
requestAnimationFrame(untimedRender);
} else {
last = performance.now();
requestAnimationFrame(timedRender);
}
}
var last;
function timedRender(timestamp) {
var delta = timestamp - last;
var then = timestamp + Math.random() * 100;
last = timestamp;
while (performance.now() < then) {}
// calculated velocity
timed += delta / 30;
document.querySelector('#timed').style.left = Math.min(Math.floor(timed), 200) + 'px';
if (timed < 200) {
requestAnimationFrame(timedRender);
}
}
requestAnimationFrame(untimedRender);
div {
position: absolute;
left: 20px;
width: 10px;
height: 10px;
}
#untimed {
background-color: #F00;
top: 20px;
}
#timed {
background-color: #00F;
top: 50px;
}
<div id="untimed"></div>
<div id="timed"></div>
请注意蓝色方块如何保持更一致的整体速度。这就是意图。
MDN 描述指出:
window.requestAnimationFrame() 方法告诉浏览器您希望执行动画,并请求浏览器调用指定的函数在下次重绘之前更新动画。
何时进行重绘在很大程度上取决于浏览器。除非在重新绘制时您的 JS 仍在运行,否则行为应该没有任何差异。
WhatWG 规范没有提到等待 JS 调用堆栈清除或类似的东西,尽管运行时间特别长的函数会阻塞 UI 线程,因此应该阻止调用动画帧。
- 删除LINES开头和结尾的空白
- Angular http.get没有'我不喜欢在开头和结尾加方括号的文本文件
- jQuery-选择以..开头和结尾的元素..但省略了具体名称
- 渐弱入/渐弱音频,指向歌曲的开头和结尾
- 匹配由单个空格分隔的单词,单词的开头或结尾不能有空格
- 如何删除字符串开头和结尾的换行符
- jquery选择以某事开头并以某事结尾
- 用于删除字符串中字符开头到结尾的正则表达式
- 从结尾或开头修剪字符串
- 正则表达式能否匹配字符串开头或结尾的字符(但不能同时匹配)
- 使用正则表达式删除段落开头和结尾的换行符
- 在字符串的开头和结尾搜索相同的数字
- 匹配开头和结尾的字词
- 用()标记替换括号的开头和结尾标记
- 正则表达式 - 字符串不能以空格开头,以空格结尾,并且连续包含几个空格
- 在字符串的开头和结尾添加一个字符
- 如何创建开头插入符号和结尾带有锚点的选择
- 如何删除正则表达式开头和结尾的空格
- 以相同元音字母开头和结尾的匹配单词
- 从字符串(JavaScript 或 PHP)的开头和结尾删除
- 标签