window.requestAnimationFrame silently fails to inv

2019-07-20 22:11发布

问题:

I am developing inside of a Google Chrome Extension. In this environment, I have the ability to inject JavaScript into third-party websites after requesting the appropriate permissions. As such, I am injecting code into an iframe referencing a cross-domain resource, but am not bound by the same cross-origin security policies as would be expected in a 'normal' environment.

The code I am executing inside of this iframe is:

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

After this code is executed, my output looks like:

Request Id: 1

The callback of requestAnimationFrame is never executed. requestAnimationFrame is defined. The callback works fine if I use a non-optimized call such as setInterval.

The callback is executed properly outside of the iframe but no security errors are shown in my console when it fails inside of the iframe. This is only for the latest version of Google Chrome -- do not worry about other implementations of requestAnimationFrame.

Are there any steps I can take to debug this issue? window.requestAnimationFrame trails off into native code and my requestId is valid... so I'm at a bit of a loss.

EDIT:

Here is the full source code for reproducing the issue as a small Google Chrome extension: https://gist.github.com/MeoMix/37b4dbdbb3bd48f3c9e2

Here is a downloadable zip of the source above: https://mega.co.nz/#!2BFA1agY!JSZC1BFBza3rU4LnqlZqcR9neZQRJn0yh1U6tu2GWo4

回答1:

Your problem has nothing to do with iframes, but with the invisibility of background pages.

Think of a background page as a non-focused tab. If you use requestAnimationFrame in a non-active tab, then the callback will not be called until the tab is focused again, as shown in the next example. Since background pages are never be "focused", RAF callbacks will never be invoked.

Paste the following code in a console, and move to a different tab. Wait a few seconds before activating the tab again. You will see that the logged timestamps in the console are very close. This shows that the callback of RAF will only be called when the tab is focused again.

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

The "solution" to your problem is to use the good old setTimeout instead:

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