为什么 requestAnimationFrame() 在帧末尾运行我的代码,而不是在帧开头?

2023-12-08

var y = 0
canvas.height *= 5
ctx.fillStyle = 'green'
function update () {
  requestAnimationFrame(update)
   ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.fillRect(0, y, 300, 300)
  y++
}
update()

对于这个简单的 JSBin (https://jsbin.com/yecowob/edit?html,js,输出) 一个正方形沿着屏幕移动,这就是 Chrome 开发工具的方式 时间线看起来:

https://i.stack.imgur.com/QqrW5.jpg

据我了解,垂直的灰色虚线是当前帧的结束和下一帧的开始。在屏幕截图中,我们有一个 19.3 毫秒的帧,其中浏览器几乎不执行任何操作(大量空闲时间)。如果浏览器在框架启动时就运行所有代码,难道它不能避免这种情况吗?

然而,如果我绘制正方形 500 次,CPU 速度会减慢 6 倍 (https://jsbin.com/yecowob/4/edit?js,输出),我得到时期 浏览器正是我想要的(开始运行代码作为框架 开始),但它再次不同步:

https://i.stack.imgur.com/vjJrW.jpg

当它开始在虚线上运行时,fps 更加平滑,但只有当浏览器有一些繁重的工作要做时我才能让它工作。

那么为什么 requestAnimationFrame() 不是每次都在帧开始时触发,我怎样才能让它这样做呢?

非常感谢您在这方面给我的任何帮助。


因为那就是requestAnimationFrame作用:它安排回调在下一个“绘画帧”触发,就在实际绘画到屏幕之前。

这里的“框架”指的是事件循环迭代,而不是视觉上的迭代,此后我将继续使用“事件循环迭代”来进行区分。

所以如果我们看一下事件循环迭代的结构正如 HTML 规范所描述的,我们可以看到“运行动画帧回调“算法是从内部调用的”更新渲染图“ 算法。
该算法负责步骤2通过检查“来确定当前事件循环迭代是否是绘画迭代渲染机会每个活动文档的“。如果不是,那么下面的所有内部步骤都将被丢弃,包括我们的“运行动画帧回调".
这意味着我们的requestAnimationFrame预定回调只会在一个非常特殊的事件循环迭代中执行:下一个带有渲染机会.

Specs don't describe precisely at which frequency this "painting frames" should occur, but basically most current vendors try to maintain 60Hz, while Chrome will make it cap to the active display's refresh rate. It is expected that Chrome behavior spreads to other vendors.


所以你描述的情况是正常的。如果你想要一个简化版本,你可以考虑requestAnimationFrame( fn ) as setTimeout( fn, time_needed_until_the_next_painting_frame )(这里的细微差别是超时回调在开始时执行事件循环迭代 while 动画帧回调最后执行)。

为什么要这样设计呢?

因为大多数时候我们希望在屏幕上显示最新的信息。因此,在绘制之前触发这些回调可确保应绘制的所有内容都位于最新位置。

但这也意味着,我们确实不应该在那里进行过于繁重的操作,以免失去绘画机会。


现在,我必须指出,有一个正在进行的提案包括一个requestPostAnimationFrame,这将安排回调在下一个“绘画帧”触发,只是after屏幕上的实际绘画。
使用这种方法,您将获得预期的行为。
不幸的是,这仍然只是一个提案,尚未包含在规格中,并且不确定是否会包含在内。

虽然它已经在 Chrome 中实现,但背后的“实验性网络平台功能“标志,我们能做的最好的事情就是在正常浏览器中处理它的行为,在下一个开始时安排一个回调事件循环迭代.
这是我制作的示例实现另一个问答:

if (typeof requestPostAnimationFrame !== 'function') {
  monkeyPatchRequestPostAnimationFrame();
}

requestAnimationFrame( animationFrameCallback );
requestPostAnimationFrame( postAnimationFrameCallback );

// monkey-patches requestPostAnimationFrame
//!\ Can not be called from inside a requestAnimationFrame callback
function monkeyPatchRequestPostAnimationFrame() {
  console.warn('using a MessageEvent workaround');
  const channel = new MessageChannel();
  const callbacks = [];
  let timestamp = 0;
  let called = false;
  channel.port2.onmessage = e => {
    called = false;
    const toCall = callbacks.slice();
    callbacks.length = 0;
    toCall.forEach(fn => {
      try {
        fn(timestamp);
      } catch (e) {}
    });
  }
  window.requestPostAnimationFrame = function(callback) {
    if (typeof callback !== 'function') {
      throw new TypeError('Argument 1 is not callable');
    }
    callbacks.push(callback);
    if (!called) {
      requestAnimationFrame((time) => {
        timestamp = time;
        channel.port1.postMessage('');
      });
      called = true;
    }
  };
}


// void loops, look at your dev-tools' timeline to see where each fires
function animationFrameCallback() {
  requestAnimationFrame( animationFrameCallback );
}
function postAnimationFrameCallback() {
  requestPostAnimationFrame( postAnimationFrameCallback )
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 requestAnimationFrame() 在帧末尾运行我的代码,而不是在帧开头? 的相关文章

  • 在 selenium webdriver 中打开一个新窗口而不是新选项卡

    当在我的应用程序中手动单击链接时 它会在 Chrome 和 IE 中的新选项卡中打开 但是 当我的脚本运行时 该链接会在 IE 中的新窗口而不是新选项卡中打开 相同的脚本在 Chrome 中按预期运行 知道如何摆脱这个吗 更改 IE 的默认
  • 正则表达式 - 匹配不包含字符串的模式

    我对正则表达式很陌生 并且一直在寻找方法来做到这一点 但没有成功 给定一个字符串 我想删除以 abc 开头 以 abc 结尾且中间不包含 abc 的任何模式 如果我做 abc abc abc 它将匹配以 b 开头 以 abc 结尾并且中间包
  • 错误:模块“html”不提供视图引擎(Express)

    我正在尝试设置一个简单的路由应用程序 但在渲染页面时不断遇到错误 Error Module html does not provide a view engine 奇怪的是我已经在 app js 文件中指定了视图引擎 但仍然收到错误 app
  • Javascript/jQuery 外部高度()

    Does idOfLememt outerHeight 对所有浏览器产生相同的结果 IE7 有什么不同吗 只要去http api jquery com outerHeight http api jquery com outerHeight
  • 我如何用 javascript/jquery 进行两指拖动?

    我正在尝试创建当有两个手指放在 div 上时拖动 div 的功能 我已将 div 绑定到 touchstart 和 touchmove 事件 我只是不确定如何编写这些函数 就像是if event originalEvent targetTo
  • 服务器响应 PASV 命令返回的地址与建立 FTP 连接的地址不同

    System Net WebException 服务器响应 PASV 命令返回的地址与建立 FTP 连接的地址不同 在 System Net FtpWebRequest CheckError 在 System Net FtpWebReque
  • Maven 构建错误 TOOLS.JAR NOT FOUND IN JRE

    我在构建 Maven 项目时遇到这个问题 请帮我解决 ERROR Failed to execute goal org apache maven plugins maven compiler plugin 2 5 1 compile def
  • Android 的代码覆盖率[重复]

    这个问题在这里已经有答案了 可能的重复 Android测试代码覆盖率 Eclipse https stackoverflow com questions 3282702 android test code coverage eclipse
  • 关闭扫描仪是否会影响性能

    我正在解决一个竞争问题 在问题中 我正在使用扫描仪获取用户输入 这是 2 个代码段 一个关闭扫描器 一个不关闭扫描器 关闭扫描仪 import java util Scanner public class JImSelection publ
  • UWP 应用程序在与商店关联后崩溃

    我正在为 Windows 创建一个 cordova 应用程序 将应用程序与商店关联后 应用程序起始页变为白色空白 如果应用程序使用包标识名称 com something moretext 则该应用程序可以正常工作 但我的商店包身份名称是 5
  • 防止 Ada DLL 中的名称损坏

    有没有一种简单的方法可以防止在创建 Ada DLL 时 Ada 名称被破坏 这是我的 adb 代码 with Ada Text IO package body testDLL is procedure Print Call is begin
  • Swift 中的 quitFirstResponder

    我怎样才能用Apple的新语言实现它 Objective C 代码 void touchesBegan NSSet touches withEvent UIEvent event for UIView view in self view s
  • Maven2继承

    如果我有一个父 pom 并且想将其继承到多个项目 我通常通过添加到项目顶部来做到这一点
  • 文本处理问题:删除其中一列不包含特定值的行

    我有一个制表符分隔的文件 如下所示 input sequence match sequence score receptor group epitope antigen organism ASRPPGGVNEQF ASRPPGGVNEQF
  • 如何用LoaderManager自动重新查询

    我有一个应用程序显示来自 SQLite DB 的数据 并且数据不断变化 所以显然 我认为我应该使用 LoaderManager 来显示数据 我读过一些关于将 LoaderManager 与 SQLite 结合使用的内容 然后看到了亚历克斯
  • 用 Beautiful Soup 进行抓取:为什么 get_text 方法不返回该元素的文本?

    最近我一直在用 python 开发一个项目 其中涉及抓取一些网站的一些代理 我遇到的问题是 当我尝试抓取某个知名代理站点时 当我要求 Beautiful Soup 查找 IP 在代理表中的位置时 它并没有按照我的预期执行操作 我将尝试查找每
  • 使用并非为 IOC 设计的遗留应用程序避免服务定位器反模式

    我经常读到IOC 中的服务定位器是一种反模式 http blog ploeh dk 2010 02 03 ServiceLocatorIsAnAntiPattern aspx 去年 我们在工作中的应用程序中引入了 IOC 具体来说是 Nin
  • JavaScript 中“键”的类型是什么?

    当我失去焦点并开始思考一个愚蠢的问题时 我遇到了这样的时刻 var a b value b 的类型是什么 我的意思不是 值 的类型 而是标记为 b 的实际键 背景 当我必须创建一个字符串键时 我开始想知道这一点 var a b value
  • RavenDB:为什么我会在此多重映射/归约索引中获得字段空值?

    受到 Ayende 文章的启发https ayende com blog 89089 ravendb multi maps reduce indexes https ayende com blog 89089 ravendb multi m
  • GAE 无法部署到 App Engine

    我正在尝试从 Eclipse 发布 Web 应用程序 我在 GAE 上创建了四个项目 可以通过登录我的帐户并查看控制台来查看它们 我已经改变了appengine web xml到项目的应用程序 ID 如果我将其更改为 GAE 上第一个创建的

随机推荐

  • 在.NET 6控制台应用程序中读取appsettings.json文件

    如何从appsettings json NET 6 控制台应用程序中的文件 program cs file public class Program private static ManualResetEvent quitEvent new
  • 如何在 Ant 中从逗号分隔的目录列表创建文件集?

    在 Ant 目标中 我获得一个属性 其中包含要包含在进一步操作 复制 过滤等 中的目录列表 它看起来像这样 directories dir1 dir2 dir3 我需要一种方法将此列表转换为选择的文件集或模式集all这些目录中的文件 我知道
  • 转换错误:需要左值作为赋值的左操作数

    所以我正在尝试使用ether aton 它返回一个struct ether addr 我正在尝试将其放入我的struct ether header eptr 来自 net ethernet h ether shost成员 我试过这个 str
  • swift3 日期到数据,数据到日期转换

    我正在努力将 Objective C 中创建的代码更改为 swift3 我想将下面的代码更改为使用 Objective c 创建的 swift3 代码 Objective c NSDate 到 NSData 代码 NSCalendar ca
  • 如何使用 PDFBox 对动态创建的 PDF 文档进行数字签名?

    对不起 我java很差 我哪里不对的地方请指正 我哪里不好的地方请改进 我正在尝试使用 PDFBox 通过以下程序对动态创建的 pdf 进行数字签名 计划中的任务 i 创建 PDF 模板 ii 更新 ByteRange xref start
  • 如何在构建阶段使用其他小部件的约束和大小

    我想确保涵盖所有情况 父窗口小部件读取 并可能使用 子窗口的大小或约束 子部件读取 并可能使用 父部件的大小或约束 子部件读取 并可能使用 另一个子部件的大小或约束 解决方案似乎是 让构建阶段运行 然后构建我想要从中检索数据的小部件的大小和
  • 本地通知?

    我的应用程序主要是服务器的客户端 实际上没有连接到互联网 它连接到 Polycom 编解码器并管理 2 个端点之间的视频通话 所以我的应用程序可以发送诸如结束通话 调高音量等命令 然而我的问题是这样的 当有来电并且应用程序不在前台时 我需要
  • Next.js Firebase 托管 404 错误(除 index.html 外)

    我构建了一个 nextjs 应用程序npm run build npm run export并使用部署到 firebasefirebase deploy命令 在此之前 我曾经使用过firebase init在我的项目文件夹中 仅使用默认选项
  • 如何将电子邮件建议传递到 Azure AD B2C 注册页面

    有没有办法在自定义策略中建议注册电子邮件 我的一些用户只需要通过邀请电子邮件进行注册 我在文档中看到 https learn microsoft com bs latn ba azure active directory b2c direc
  • ViewStateUserKey + 共享托管 + ViewStateMac 验证失败

    所以 问题很简单 尽管我开始怀疑这是否会得到解答 我有一个网站 我想在其中使用推荐的 ViewStateUserKey 来保护我的视图状态 在我的基页 显然继承自 Page 中 我有以下代码 protected override void
  • 保留最新文件并删除所有其他文件

    在我的文件夹中有许多具有日期时间戳格式的 pdf 文件 如最后所示 我想保留当天的最新文件并删除当天的其余文件 我该怎么做 2012 07 13 15 13 27 1342167207 pdf 2012 07 13 15 18 22 134
  • 为什么 Java 在连续整数上切换似乎在增加情况下运行得更快?

    我正在编写一些需要高度优化的 Java 代码 因为它将在主程序逻辑中的许多点调用的热函数中运行 该代码的一部分涉及乘法double变量由10提升为任意非负数int exponents 获得相乘值的一种快速方法 编辑 但不是最快的方法 请参阅
  • BlackBerry 应用程序大于 14mb

    我的黑莓应用程序包括一些 html 文件 图像 jss 文件 这些文件是gzip压缩的 但是这个gzip的大小是18mb 我知道 BlackBerry 智能手机应用程序的最大大小是约14MB 我该如何解决这个限制 我找到了这个支持论坛页面
  • Crystal Reports - “您请求的报告需要更多信息”

    我有一些使用 Crystal Visual Studio 外部 创建的 Crystal Reports 现在已加载到 VS 项目中 在预览报告之前 我在报告和所有子报告中设置了这样的报告数据库信息 var connectionInfo ne
  • 在 Azure DevOps Powershell 管道任务中获取自己的服务主体名称

    当使用 system debug true 在 Azure DevOps 发布管道中运行 Azure Powershell 任务时 您将获得类似于以下内容的输出 anonymized 2019 09 05T12 19 41 8983585Z
  • Excel 日期值

    如何将日期字符串 2019 06 20T00 00 00 01 00 转换为 Excel 日期 当我在 Excel 中尝试此操作时 DATEVALUE 返回 Value 日期字符串来自C DateTime ToShortDateString
  • dyld`__abort_with_payload:没有错误消息

    当我使用 Xcode 启动应用程序时 出现崩溃 但没有错误 该应用程序刚刚停止在此线程上 我可以做什么来获得有关该问题的更多信息 如果您使用自定义框架 则需要将其放入 Xcode 项目中 目标 常规 选项卡下的 嵌入式二进制文件 部分
  • 如何在栅格之间进行插值?

    如果有三个栅格 作为矩阵 r1 lt raster nrows 10 ncols 10 r1 lt setValues r1 1 ncell r1 r16 lt raster nrows 10 ncols 10 r16 lt setValu
  • Android 光标位于业务对象的通用列表上?

    在 NET 领域 我通常会查询数据库并填充通用列表类型的集合 然后应用程序将使用它 在 Android 领域 我一直在阅读有关应用程序中的数据库访问和使用的内容 为什么大多数文档都显示游标的使用以及使用常量来访问它 也许这是为了节省资源 也
  • 为什么 requestAnimationFrame() 在帧末尾运行我的代码,而不是在帧开头?

    var y 0 canvas height 5 ctx fillStyle green function update requestAnimationFrame update ctx clearRect 0 0 canvas width