Allow requestAnimationFrame to run in background tab if pop up window opened from that tab is visible |
||||||||
Issue description
Enable executing requestAnimationFrame from a hidden background tab if a popup window opened from that tab is visible.
requestAnimationFrame should be kept consistent for units within same SiteInstance. Specifically for Slides, this needs to work for pop ups opened via window.open("", ...) and for pop ups opened from within an iframe.
See more details here (Google internal only): https://docs.google.com/document/d/19gNt_SpEJJm1RC38y0L6yxarEYAzn189d5FoecxBQeM/edit
,
Jul 11
If I understood the case correctly from the linked doc, the opener tab is relying on rAF to running in another window, which is hidden and not being cast/displayed anywhere, right? Chrome and other browsers are increasingly strict about not running rAF in cases where the output can't be seen by anyone (e.g., offscreen iframes), because it's really easy to accidentally waste a lot of power by doing that. This feels like another case where leaving rAF running can have a high cost. Also, a completely backgrounded tab (but not yet an occluded window) won't have any compositing resources, so we'd have to come up with some kind of fake rAF loop that makes it look like things are animating. This is pretty tricky for things like CSS animations which are driven off the main thread. I wonder if there's another way around the problem? I could see us having a policy that keeps timers running unthrottled in hidden windows that are being scripted by a foreground window, but that won't solve the issue if you need things like CSS animations to run too.
,
Jul 11
The opener tab is hidden. The pop up window is visible. Since the pop up window is visible, the output of rAF will be seen by user. Correct, we need animations to run.
,
Jul 12
Ah, I think I had the opener relationship backwards. But still, the problem is that rAF isn't running in the hidden opener tab, right? Or is there an issue with rAF in the pop up window?
,
Jul 12
Right, the problem is that rAF isn't running in the hidden opener tab.
,
Jul 16
,
Jul 16
,
Jul 16
Reproduction from internal doc: http://jsfiddle.net/k9fgw2nL/6/ Outcome from various browsers (non-Linux platforms using browserstack, so please lmk if you can't reproduce the same results as me on a real platform): Chrome 69.0.3486.0 (Linux): Does not show the text until you switch back to the tab. Firefox Nightly 63 (Linux): Shows the text after a small delay (0.5-1 second) Edge Insider Preview 10 (Windows 10): Does not show the text until you switch back to the tab. Safari 11.1 (High Sierra): Does not show the text until you switch back to the tab. Given that the browsers mostly align on behavior, I suspect changing this would require clear evidence that this is desirable behavior (I can naively see some potential for abuse with tiny pop-up windows allowing hidden pages to keep running rAF and thus avoid throttling). Assigning to flackr@ (Animations TL) for comment.
,
Jul 16
The spec seems pretty clear that requestAnimationFrame callbacks are sampled when that document's animations are sampled, and the algorithm explicitly skips documents whose visibilityState is not visible by the Animation Timing Processing Model[1]. I actually suspect that Firefox is not spec compliant in this regard but probably made a concession to continue to run background tasks at a low rate. Also, hypothetically if we did want to change this, I worry that it forces us to service animations for all windows to occur at the same time even though they could be on different monitors with different vsync times or potentially different refresh rates (in addition to potentially updating animations on hidden tabs). If for your application you observe the visibility state, you should be able to tell whether to expect a raf, note that in general you'd likely need to observe the visibility state change to avoid a race in the case that the user is currently minimizing that tab. Then you can tell whether you should wait for an animation frame or not. [1] https://www.w3.org/TR/animation-timing/#processingmodel
,
Jul 16
In the slides usecase - could you clarify if the main slides window is obscured (full occlusion) by the speaker notes window or it is actually "hidden" i.e. background / minimized tab? Also what is the visibilityState that is reported on the main window? These cases are different for "visibilityState": currently full occlusion is not considered "hidden" in the spec but this change will make it so that UA can decide to indicate this as "hidden": https://github.com/w3c/page-visibility/pull/38 Basically, it is not trivial to detect full occlusion on every platform, therefore it is optional and up to the UA and spec'd as "may be hidden when fully obscured".
,
Jul 16
,
Jul 17
The user can do anything with the opener and pop-up, so ideally all cases work as long as the pop-up is visible. The visibility state reported on the main window is as follows on Chrome 68.0.3440.59 (see http://jsfiddle.net/7n6xu218/1/ for onclick instrumentation): 1) If pop-up is full screen - visibility state in onclick "visible" 2) If pop-up is fully occluding the opener - visibility state in onclick "visible", visibility state in chrome://discards "occluded" 3) If Opener tab can be in background - visibility state in onclick "hidden", visibility state in chrome://discards "hidden"
,
Jul 17
Re #10, isn't all that matters is whether the browser thinks that it should fire rAF, as long as this matches visibility state you should be able to do something like the following:
function pseudoRAF(callback) {
let raf;
const assumeFrameProduced = function() {
cancelAnimationFrame(raf);
document.removeEventListener("visibilitychange", assumeFrameProduced);
callback();
}
if (document.visibilityState != 'visible') {
assumeFrameProduced();
} else {
// Observe either rAF or visibility state changing.
raf = requestAnimationFrame(assumeFrameProduced);
document.addEventListener("visibilitychange", assumeFrameProduced);
}
}
This will fire the callback when the tab is/becomes hidden or a frame is produced.
,
Aug 23
In the example from #8, the animation frame provider is the same for the main window and the child window, since they have the same JS context. Therefore I think they couldn't pump frames at different rates on different monitors, which was a concern raised in #9. Also, since they have the same animation frame provider, and one of the windows is visible, why don't we just consider both windows visible? This would solve the problem neatly. Both the popup window and its parent would keep their compositing resources and rAF loops during this state.
,
Aug 24
,
Sep 6
My different frame rate concern in #9 is a conceptual one. We could hypothetically pump the different window lifecycles at different times. I agree we probably could do this, but I still don't think it's the right thing to do. It's not what any browser does. I created a fork http://jsfiddle.net/flackr/ac30nhvo/ which times the raf: - Chrome fires it when the window becomes visible. - Safari fires it when the window becomes visible. - Firefox eventually fires it up to 1000ms later. This is likely as I hypothesized in #9 because they still eventually fire rAF in background frames. - Edge fires it when the window becomes visible. I think implementing this correctly means that we'd need to update the page rendering for those windows which aren't currently visible. I worry that there are many cases where this is not the desired behavior. For example, in Google drive wouldn't every document I open from the same drive window in background tabs need to be kept alive? Also, there's a simple workaround. If you have the same JS context you can just call requestAnimationFrame in the child window (e.g. myWindow.requestAnimationFrame in the example in #8). Since they fire at the same time currently for windows having the same JS context it will fire at the expected time.
,
Sep 6
Oops, didn't realize the per-browser behavior was already demonstrated in #8.
,
Sep 7
Example using myWindow.requestAnimationFrame: http://jsfiddle.net/flackr/4evw2cbm/
,
Sep 7
Closing as WontFix, since flackr's proposed workaround seems very simple and works.
,
Sep 7
And also there are good arguments for not running rAF on backgrounded windows. |
||||||||
►
Sign in to add a comment |
||||||||
Comment 1 by cbiesin...@chromium.org
, Jul 10