Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web Workers in Chrome v54 run twice as slow when running in an inactive tab

I have a webapp that plays audio with fade in/out transitions using setTimeout. It is well known that chrome and other browsers throttle setTimeout execution when it is running in an inactive (or background) tab. So to solve this issue, I use this script (https://github.com/turuslan/HackTimer) which patches the Timer API to use Web Workers instead. This allows the volume fading transitions to run in the background so that they will always be executed and completed in the same time regardless if the tab is active. This used to work great in chrome, but now I have noticed that in version 54 (and probably earlier versions) of chrome, the Web Workers are being executed twice as slow when running in an inactive tab. This issue does not happen and works perfectly with FireFox and even IE11!

Is this a chrome bug? Or is it intended behavior? Is there another workaround to this issue? I don't want to require that the webapp to be opened in a separate window, so that is not an option.

Here is a demonstration: https://jsfiddle.net/2614xsj8/1/

// Open Chrome console and run this then wait a few seconds to see
// it is executing on time. Then open or switch to a new tab and wait
// a few seconds. Come back to see how much slower the setTimeout
// function was being called even when using HackTimer which patches
// the Timer API to use Web Workers

var rate = 1000;
var start = new Date().getTime();
var func = function() {
  var now = new Date().getTime();
  var time = now - start;
  var status = Math.abs(rate - time) <= 50 ? "on time" : (time / rate) + " times slower";
  console.log("executed in [" + time + "] milliseconds. " + status);
  start = now;
  setTimeout(func, rate);
};
setTimeout(func, rate);
<script src="https://cdn.rawgit.com/turuslan/HackTimer/master/HackTimer.js" type="text/javascript"></script>
like image 929
Jon McPherson Avatar asked Nov 07 '16 21:11

Jon McPherson


1 Answers

Using Task Scheduler would be the best way to do it then you don't really on timeout or interval but a specific date

But this requires using service workers instead... which is a bummer. cuz then your site also needs to be whitelisted in order to run service workers (so your site needs a valid SSL cert)

// https://example.com/serviceworker.js
this.ontask = function(task) {
    alert(task.data.message);
    console.log("Task scheduled at: " + new Date(task.time));
    // From here on we can write the data to IndexedDB, send it to any open windows,
    // display a notification, etc.
}

// https://example.com/webapp.js
function onTaskAdded(task) {
    console.log("Task successfully scheduled.");
}

function onError(error) {
    alert("Sorry, couldn't set the alarm: " + error);
}

navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.taskScheduler.add(Date.now() + (10 * 60000), {
        message: "It's been 10 minutes, your soup is ready!"
    }).then(onTaskAdded, onError);
});
like image 87
Endless Avatar answered Nov 01 '22 21:11

Endless