image_pdfimage_print

Most web developers would probably agree: It’s a much better user experience when the data behind the application is automatically updated. Depending on the nature of the data, these refreshes could happen every couple of seconds, every minute, every couple of minutes, or sometimes even hours. All that’s required is a simple timer to periodically re-fetch the data so what’s displayed is up to date. 

On a more complex portal, there could easily be two dozen sources of data refreshed. This introduces stress on the backend services and could even be considered a bit wasteful. However, it’s better than forcing the user to do manual refreshes when they want to be sure that they’re looking at the latest version of some data source.

So, what’s the solution?

The Hypothesis

At the Pure Storage Hackathon in May 2023, I wondered this. Is there a way to limit data traffic for our customer-facing application without impacting user experience? 

I focused on the timer behavior when the page is hidden (e.g., an inactive browser tab). Page visibility changes can be easily obtained from the page visibility API, so I simply logged the number of visible/hidden requests to our analytics tool. I didn’t want to influence user experience when they checked another tab quickly, so I considered a page “hidden” only when it was not visible for more than 15 seconds.

The First Attempt

The results were pretty surprising. Around 80% of web requests were happening when the page was hidden. The question then became: Can we eliminate these requests in a smart way? 

My first idea was to use http interceptor and delay execution of requests when the page is not active. But, since we also decided that we would rather increase the interval than eliminate updates completely, that would be pretty complicated, especially if some requests depend on each other, which could easily deadlock the whole application. 

Other requirements were the ability to immediately trigger a refresh when a user revisits the window, and also not to interfere with requests that should continue even when hidden (such as auth requests). 

So, while the interceptor would be easy to deploy for all requests, I decided that it would be pretty hard to make it work without negative side effects. 

The Second Attempt

My second idea proved to be much more feasible. Most refresh requests were implemented as rxjs timer or interval observables. I realized that I could make a custom timer that would only have logic to emit based on page visibility. 

Implementation turned out to be surprisingly fast and elegant. Because I needed to replace every occurrence of rxjs timer and interval, it would be best if this new timer would have an order of arguments as similar as possible to one another. This would make find and replace much easier, which turned out to be a good decision. 

After some testing, I was able to easily replace all existing timers and also write eslint rules that would warn about future use of rxjs timer or interval and, instead, suggest it use this new observable that I called “smart timer.”

The only thing left to do was the production deployment.

Web Requests by 70%

Figure 1: Test results for the number of web requests to the application.

To my relief, the number of requests decreased quickly, proving the solution works. After some time, the number of requests stabilized at around 30% of past volumes. This is a pretty great result considering the relatively small amount of work needed and no disadvantages of this approach.

Then, I started thinking about how a smart timer could benefit other Pure Storage front-end applications. I didn’t want to copy around one file, so I needed to create a npm package. Then, I thought about making this utility open source, as almost everyone could benefit from cutting down unnecessary requests without lowering customer experience. 

My managers at Pure Storage were very supportive so the smart-timer is now fully open source under Apache-2.0 license on GitHub. To install it, simply use command “npm i @pstg/smart-timer.

I hope you’ll give it a try and that it has the same positive effect on your app as it had on ours!