【问题标题】:window.requestAnimationFrame silently fails to invoke callback, but generates a valid requestID, when invoked inside of a cross-domain iframewindow.requestAnimationFrame 在跨域 iframe 内调用时静默调用回调失败,但会生成有效的 requestID
【发布时间】:2014-01-14 11:40:25
【问题描述】:

我正在使用 Google Chrome 扩展程序进行开发。在这种环境下,我可以在请求适当的权限后将 JavaScript 注入第三方网站。因此,我将代码注入到引用跨域资源的 iframe 中,但不受“正常”环境中预期的相同跨域安全策略的约束。

我在这个 iframe 中执行的代码是:

var requestId = window.requestAnimationFrame(function(){
    console.log("Success");
});
console.log("Request Id:", requestId);

这段代码执行后,我的输出如下:

请求 ID:1

requestAnimationFrame 的回调永远不会被执行。 requestAnimationFrame 已定义。如果我使用 setInterval 等非优化调用,回调可以正常工作。

回调在 iframe 之外正确执行,但当它在 iframe 内失败时,我的控制台中不会显示任何安全错误。这仅适用于最新版本的 Google Chrome —— 不要担心 requestAnimationFrame 的其他实现。

我可以采取任何步骤来调试此问题吗? window.requestAnimationFrame 进入本机代码,我的 requestId 是有效的......所以我有点茫然。

编辑:

以下是将问题重现为小型 Google Chrome 扩展程序的完整源代码:https://gist.github.com/MeoMix/37b4dbdbb3bd48f3c9e2

这是上述源代码的可下载 zip:https://mega.co.nz/#!2BFA1agY!JSZC1BFBza3rU4LnqlZqcR9neZQRJn0yh1U6tu2GWo4

【问题讨论】:

  • 您能否提供有效的代码和页面来重现该问题?页面是否覆盖了 RAF?例如。 window.requestAnimationFrame=function(){return 1;};?
  • 我 console.log'ed window.requestAnimationFrame 并且控制台指示该函数的主体是本机代码。我假设这意味着它没有被存根。今晚我将制作一个工作示例并更新我的帖子——抱歉缺乏可靠的信息。如果有任何帮助 - 我将代码注入到 YouTube API 生成的 iframe 中。
  • 这不太可能,但并非不可能。而“[native code]”并不能告诉你太多。 window.requestAnimationFrame = (function(){return 1;}).bind(null); 会显示相同的行为,并且还会显示“[native code]”。
  • 有趣,TIL。本机代码实际上表明了什么?我以为它正在我的 GPU 上或者什么时候可以再次渲染。
  • “原生代码并不能告诉你太多”,我的意思是任何人都可以创建一个序列化为“function() { [native code] }` 的函数。如果你看到”[native code ]”,只是将其读作“无法序列化函数的源代码”。

标签: javascript iframe google-chrome-extension cross-domain


【解决方案1】:

您的问题与 iframe 无关,而是与背景页面的不可见性有关。

将背景页面视为非焦点标签。如果您在非活动选项卡中使用requestAnimationFrame,则在选项卡再次获得焦点之前不会调用回调,如下例所示。由于后台页面永远不会被“聚焦”,因此永远不会调用 RAF 回调。

将以下代码粘贴到控制台中,然后移至其他选项卡。等待几秒钟,然后再次激活选项卡。您将看到控制台中记录的时间戳非常接近。这说明只有在tab再次获得焦点时才会调用RAF的回调。

setTimeout(function() {
    console.time(1);
    console.time(2)
    requestAnimationFrame(function() {
        console.timeEnd(1)
    });
}, 2000)
window.onfocus = function() {
    console.timeEnd(2);
};

您的问题的“解决方案”是改用旧的setTimeout

setTimeout(function() {
    console.log('Success');
}, 25); // 40 Hz.

【讨论】:

  • 有趣。我不知道。是的,我绝对可以使用 setTimeout。我只是认为使用 requestAnimationFrame 可以轻松提高性能。感谢调查!!
  • 你刚刚救了我的命!!!我试图在扩展的后台脚本中使用 tracking.js,我没有收到任何错误,但它也不起作用!现在我可以更改 tracking.js 代码并完成我的项目。谢谢!
猜你喜欢
  • 2013-11-27
  • 2017-03-31
  • 1970-01-01
  • 2021-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
  • 1970-01-01
  • 2021-10-04
相关资源
最近更新 更多