5 ms·
I run a real time charting platform for Bitcoin traders (like those using BitMEX) and the app does a lot of updating/refreshing. I recently learned of the visib
by artursapek 10y ago
I run a real time charting platform for Bitcoin traders (like those using BitMEX) and the app does a lot of updating/refreshing. I recently learned of the visibilitychange API and managed to make huge improvements in the app's performance when running in the background - on the order of ~75% reduction in CPU usage when running in the background. [1]
var doVisualUpdates = true;
document.addEventListener('visibilitychange', function(){
doVisualUpdates = !document.hidden;
});
Basically, you can use this to determine if your tab is running "in the background" and avoid redrawing/refreshing components to show updates that won't ever be seen.
[1] https://twitter.com/cryptowat_ch/status/817502626896089090 https://twitter.com/cryptowat_ch/status/817502626896089090
- STRML 10y agoYeah - that's a really great trick! You can also get this somewhat "for free" by batching updates on `requestAnimationFrame`, which never fires when unfocused. https://www.npmjs.com/package/visibility https://www.npmjs.com/package/visibility is a nice little package that encapsulates some of the browser compat issues, if you have out-of-date clients.
- artursapek 10y agoBut if you do this, isn't it possible that you'll queue up tons of re-renders that all go off when the tab comes back in focus? I'm thinking of React for example, where you might re-render a component with updated props several times per second. In my case, I've settled on just not re-rendering at all, and then doing so once with the latest props when "visibility" fires again with document.hidden === true.
- STRML 10y agoThis is where batched rendering really comes in handy. For example: https://gist.github.com/STRML/cc368c46c2d7de8679196e69ddbcaef7 https://gist.github.com/STRML/cc368c46c2d7de8679196e69ddbcae... The key is, even in your case (with price alerts), you'll still want to tick occasionally, thus the `FORCE_TICK_INTERVAL`. React's own batching is smart enough to merge the work. For example, before the next tick, one component calls setState() 20 times, another calls it once. Only one rerender will actually be done. Some more discussion on rAF batching here: https://github.com/petehunt/react-raf-batching/issues/8 https://github.com/petehunt/react-raf-batching/issues/8
- just2n 10y agoWhy not limit it to a single render queued with the latest information? I see this done via debouncing for render operations that happen on repeated events, for instance typing (send query to server, then show matching results in a render of some list).
- SapphireSun 10y agoI'm not a graphics expert, but one really easy change to make is a pattern like this: _needsrender = false; function render () { _needsrender = true; } requestAnimationFrame(function hardrender () { if (_needsrender) { .... do stuff .... _needsrender = false; } requestAnimationFrame(hardrender); });
- Kiro 10y agoYes, this happens in my browser games. When the user clicks back to the tab it fires off all the frames that have been queued up, moving everything in hyperspeed until it's up to date. I don't really mind though, since it's multiplayer it's supposed to catch up but doesn't need to render when unfocused.
- benjaminjackman 10y agoWow that's a great tip, I did not know about that one, but it's going to be very useful for a UI I am about to start working on. In addition to requestAnimationFrame this could be very handy! Are there any gotchas you have experienced in using this API that I should look out for?
- artursapek 10y agoJust look out for this not being supported and make sure your stuff still works. Eg, document.hidden might be undefined so don't initialize like this: doVisualUpdates = (document.hidden === true);
- minitech 10y agoWell, you’d typically want to do visual updates when document.hidden wasn’t true, which would work fine.
- ErikBjare 10y agoHe probably meant `(browser.hidden === false)` which wouldn't work if browser.hidden is undefined. Use == instead of === and it will work fine.
- minitech 10y ago`!document.hidden` would work, and it’s what most people would normally write already. `document.hidden == false` would not work; `false != undefined`.
- artursapek 10y agoNo, the opposite of that. If document.hidden === undefined, you don't want to use this optimization at all. What I was saying is, if you initialize doVisualUpdates as "document.hidden === true", in the case where it's undefined, you will never do visual updates.
- skilgarriff 10y agoIf you happen to use React, I built a React component that helps you manage this! :) Hopefully it helps a bit! It also reports whether or not a user is idle, such that you can reduce cpu usage during that as well. https://github.com/Skilgarriff/react-user-focus https://github.com/Skilgarriff/react-user-focus
- LeanderK 10y agoi don't know anything about React, but why can't react itself try to manage this?
- STRML 10y agoReact is in the business of limiting its API surface, not increasing it. I think they have done a great job of it - libraries like this should exist in userland.
- cpeterso 10y agoIt seems like React could listen for visibilitychange itself to throttle its own events or virtual DOM processing. It wouldn't necessarily need to expose visibilitychange as a library API.
- KirinDave 10y agoBecause there is no sufficient magic for that. App developers have to think about when they do work, how much work they do, and if and when it should be rendered. For any rule you can give, I can give you an example of an app that would break. In general, the mantra for people who find this tough to fix should be, "Why didn't I use MVC, what a cretin I was!"
- daveheq 10y agoWhy should the browser rely on the webpage developer to tell it to not redraw things in a tab that isn't the visible one? The browser by default shouldn't redraw content in a tab that isn't visible. This seems like the most obvious thing in the world.
- vertex-four 10y agoIt doesn't need to do the final step of rendering - but it still needs to reflow the page whenever you change the DOM, because information from that reflow is accessible to javascript.
- Filligree 10y agoIt depends on how you define "Visibility changes". What might he be talking about? Well, it works something like this... - The app fetches data from a server. - The data is processed. This may be cheap, or expensive. - The DOM is updated. - The page layout is recomputed. - The browser window is redrawn. Certainly, the browser could skip the last step for invisible tabs. It can't skip redoing the layout, as the JS can read the computed layout back out; at most it could do the computation lazily, but that would be extra code and complexity. Everything prior to that step isn't under the browser's control. The web-app coder could act on every single step in the chain, starting by throttling data fetches.
- odbol_ 10y agoBecause some websites might still need to work when not in focus. E.g. If you are showing animations or videos in a window, but the user wants to answer an IM in another window without interrupting the animations.
- 72deluxe 10y agoBut then if you switch windows or tabs, the timer for the animations in the tab that is now invisible can be stopped, surely?? Why redraw an invisible window? In any ordinary paint routine, you query for the invalidated rectangle and only redraw what you must. In the case of pages that are out of view, then nothing needs redrawing. Processes that are busy doing things they need not (like redrawing on a timer, polling a mouse) is why Apple starting highlighting offenders in macOS (what is hogging the battery??) and why I don't use Chrome on it - it just gobbles power keeping all of those tabs alive. Hopefully these new changes will help.
- nkkollaw 10y agoVery nice.
- glenscott1 10y agoThis is a great tip. To make it compatible with most modern browsers (Chrome, Firefox, Opera, Safari and MS), you'll need to use the following checks: if (typeof window.document.hidden !== 'undefined') { hidden = 'hidden'; } else if (typeof window.document.msHidden !== 'undefined') { hidden = 'msHidden'; } else if (typeof window.document.webkitHidden !== 'undefined') { hidden = 'webkitHidden'; } doVisualUpdates = !window.document[hidden]; reference: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibi...
- swah 10y agoYou site is beautiful, very much like HN in the sense of showing lots of information vs following design trends: https://cryptowat.ch/ https://cryptowat.ch/
- conradfr 10y agoOn the other hand, it gives us video ads that stop and resume when tabs are switched.
- trakout 10y agoFor animations/any sort of render loop, you can also make use of the requestAnimationFrame API, which auto-pauses when the tab is out of focus. https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame https://developer.mozilla.org/en-US/docs/Web/API/window/requ...