hashi Posted January 22, 2017 Share Posted January 22, 2017 I've implemented `Timer` class for high accuracy timing (for example for update logic/game-loop, sending ping each 15 seconds by WebRTC etc.) setTimeout/setInterval fires once per second when tab is inactive, so how to gain accuracy timing? We could set up `setTimeout/setInterval` in WebWorker, because in WebWorkers when tab is inactive, `setTimeout/setInterval` still fires with it's own interval/delay. We could then send message `postmessage/onmessage` from WebWorker to Main Thread on each `setTimeout/setInterval` fire calls as a tick. For some time this idea was working and was brilliant, but when I'm looking now (latest chrome version) this isn't working anymore because of `postmessage`, now `postmessage` delivers event with delay when tab is inactive.. Looks like Chrome Dev Team noticed this feautre, and they've fixed it.. but it wasn't a bug? gaah.. or maybe I have something wrong in the code: https://jsfiddle.net/mfzmotb1/16/ Timer = function Timer(callback, interval) { var id = Timer.prototype.__idCounter++; Timer.prototype.__hash[id] = callback; this.started = false; this.package = JSON.stringify({ id: id, interval: interval }); } Timer.prototype.__workerScript = function() { var __hash = {}; onmessage = function(ev) { var data = JSON.parse(ev.data); if ( __hash[data.id] === undefined ) { __hash[data.id] = { id: data.id, lastTime: performance.now(), interval: data.interval, step: 0 } } else delete __hash[data.id]; } function loop(start) { if ( !start ) for ( var id in __hash ) step(__hash[id]); setTimeout(loop, 0); } loop(true); function step(unit) { while ( performance.now() - unit.lastTime >= unit.interval ) { unit.lastTime += unit.interval; unit.step++; var now = Date.now(); console.log("ww", unit.step, "-", now/1000); postMessage(JSON.stringify({id: unit.id, time: now, step: unit.step})); } } } Timer.prototype.__idCounter = 0; Timer.prototype.__hash = {}; Timer.prototype.__worker = new Worker(URL.createObjectURL(new Blob(['('+Timer.prototype.__workerScript.toString()+')()'], {type: 'application/javascript'}))); Timer.prototype.__worker.onmessage = function(ev) { var data = JSON.parse(ev.data); Timer.prototype.__hash[data.id](data.time, data.step); } Timer.prototype.start = function(){ if ( !this.started ) { Timer.prototype.__worker.postMessage(this.package); this.started = true; } } Timer.prototype.stop = function(){ if ( this.started ) { Timer.prototype.__worker.postMessage(this.package); this.started = false; } } var timer = new Timer(function(wwTime, step) { var now = Date.now(); console.log("m_", step, "-", wwTime/1000, now/1000, (now-wwTime)/1000); }, 100); console.log("starting in 2sec, so you have time to switch tabs"); setTimeout(function() { timer.start(); }, 2000); Basically this code produce new class called `Timer`, there is WebWorker based on one function body `Timer.prototype.__workerScript` <- this fn's body happens in WebWorker. One WebWorker handles all instances of Timer, each instance is for one timer. Any ideas how to fix it? Here goes output: Some tips: ww - console.log called from webworker m_ - console.log called from main thread 1,2,3 - number of timer step Tab Active: starting in 2sec ww 1 - 1485111848.697 //webworker tick time in seconds m_ 1 - 1485111848.697 1485111848.707 0.01 //webworker tick time, main thread tick time, diff ww 2 - 1485111848.798 m_ 2 - 1485111848.798 1485111848.799 0.001 ww 3 - 1485111848.898 m_ 3 - 1485111848.898 1485111848.898 0 ... Tab Inactive: starting in 2sec ww 1 - 1485110821.95 //webworker tick time in seconds ww 2 - 1485110822.049 ww 3 - 1485110822.149 m_ 1 - 1485110821.95 1485110822.169 0.219 //webworker tick time, main thread tick time, diff m_ 2 - 1485110822.049 1485110822.17 0.121 m_ 3 - 1485110822.149 1485110822.171 0.022 ... Do you know any ideas for measuring time for html5 gaming without throttle? Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.