5

I am building a progressive web app using React, the concept of which revolves around keeping a timer running.

For context, the app is for home-brewers to keep track of when hops and other additions need to be added to their boil during their brew. Additions are added with a certain amount of time remaining in the boil, i.e. 1 oz Citra hops at 20 minutes remaining.

I'm using JavaScript's setInterval to "tick" the timer, which is an elapsedSeconds state property that drives the rest of the application.

The problem I'm running into is when the timer stops ticking. If I let the app run, the screen will eventually lock, or I'll switch apps, etc. The service worker will continue running, and the timer will continue to tick, for a short time (about 10 minutes from what I can tell in testing?)

My thought is that I will store an epoch time in state, that represents the time when the timer started. That way, when a user "returns" to the PWA, I can compare the current epoch time against the stored startingEpochTime to get the elapsedSeconds back. But I don't want to do this comparison at every "tick" if I don't have to. Ideally, this comparison would only run when the user is returning to the application from some other context, after the service worker has already stopped processing.

What I'm looking for is the correct way to do this. Would window.onload work in this instance? If I switch apps to another app for 20 minutes then switch back to my timer app, is that method run again? Looking for the best practice for this sort of scenario, or any idea that might help me out.

Graham Bewley
  • 195
  • 3
  • 13
  • what's the reason you don't want to store the starting time? what's the benefit of `setInterval` compared to storing the starting time? – mrReiha Oct 05 '19 at 01:04
  • No problem storing the starting time, I just don't want to have to use the comparison between current time and starting time each second if I don't have to. Ideally I can harness ```setTimeout``` to handle that during normal app operation, then use the epoch time comparison when the app is re-opened if that makes sense. – Graham Bewley Oct 05 '19 at 01:12
  • 1
    I wrote a timer myself a few months ago ( [TimeRunner](https://github.com/mrReiha/TimeRunner/) ), and the final solution I came up with was mixing some different tricks. I do the tick, not even once in a second, but as satisfying as frame-rate is capable. I'm using `requestAnimationFrame` to make my frames. And each time I calculate the difference because it's just safer; `setInterval` is not that reliable. – mrReiha Oct 05 '19 at 01:24
  • And I do think, serviceWorker at the background of your PWA will take a peek once in a while after that 10mins you've mentioned. So it's perfect to always set a timeout for the finishing time whenever your ticking function is called. I had no luck to find an assured solution, but this is what I think it's closest to secure. – mrReiha Oct 05 '19 at 01:30
  • @mrReiha So you're saying that in your ```requestAnimationFrame```, you're comparing some sort of ```startSeconds``` variable against ```currentSeconds```, based on a new JavaScript Date object, each time? That sounds like it could work for me, just seemed like a lot of overhead. Thank you. – Graham Bewley Oct 05 '19 at 12:49
  • 1
    Yeah, that's exactly what I'm saying. and indeed it's an overkill for a timer, but this way you can assure that you're showing the right time. – mrReiha Oct 05 '19 at 15:22
  • Check this question, it's similar - https://stackoverflow.com/questions/5927284/how-can-i-make-setinterval-also-work-when-a-tab-is-inactive-in-chrome – Elijah Seed Arita Oct 07 '19 at 20:11

2 Answers2

1

As of 2022 there is no way of scheduling tasks or keeping a timer running when a PWA is moved into the background.

To everyone who wants this functionality, please star and comment on the Google issue requesting it to motivate them to act: https://bugs.chromium.org/p/chromium/issues/detail?id=889077

Richard
  • 14,798
  • 21
  • 70
  • 103
0

Here's a couple of pointers that can help:

The general solution to what you describe is the Wake Lock API, which is the process of being design and specified, but is not available anywhere by default (yet).

In terms of what's currently implemented, there are pretty reliable ways of at least detecting when your web app goes into the background and goes back into the foreground using the Page Lifecycle API events. Once you're reliably detecting when you've come back to the foreground, a technique like what's mentioned in the comments about comparing the start time to the current time sounds about right.

Jeff Posnick
  • 53,580
  • 14
  • 141
  • 167