2016-07-10 20 views
8

Ho un cronometro principale con 4 mini-cronometri per ogni passo. Dopo un tempo finito, ecco un esempio di come i timer dovrebbe guardare:Cronometro con punti di interruzione non sommati correttamente

MAIN: 00 : 14 : 57 
------------------- 
MINI1: 00 : 04 . 17 
MINI2: 00 : 06 . 40 
MINI3: 00 : 02 . 54 
MINI4: 00 : 01 . 46 

I mini-timer dovrebbero aggiungere fino al timer principale, come fanno in questo caso. Con il mio attuale timer, sembra sempre essere spento .02 millisecondi, quindi in questo caso si sommano a 00 : 14 . 55 anziché a 00 : 14 . 57.

Questo è un JSFiddle dei timer correnti. Penso che il problema sia molto probabile nel file stopwatch.js, ma non sono sicuro del motivo per cui sarebbe il caso poiché sto usando Date.now() per calcolare quanto tempo è passato. Ecco il file stopwatch.js che è il codice per un cronometro individuale:

class Stopwatch { 
    constructor (opts) { 
    this.isOn = false; 
    this.time = 0; 
    this.elem = opts.elem; 
    } 

    start() { 
    this.offset = Date.now(); 
    this.interval = setInterval(() => this._update(), 10); 
    this.isOn = true; 
    } 

    stop() { 
    clearInterval(this.interval); 
    this.offset = null; 
    this.interval = null; 
    this.isOn = false; 
    } 

    reset() { 
    this.time = 0; 
    this._render(); 
    } 

    _update() { 
    this.time += this._getTimePassed(); 
    this._render(); 
    } 

    _getTimePassed() { 
    const now = Date.now(); 
    const timePassed = now - this.offset; 
    this.offset = now; 
    return timePassed; 
    } 

    _timeFormatter (milliseconds) { 
    const padZero = (time) => `0${time}`.slice(-2); 

    const minutes = padZero(milliseconds/60000 | 0); 
    const seconds = padZero((milliseconds/1000 | 0) % 60); 
    const centiseconds = padZero((milliseconds/10 | 0) % 100); 

    return `${minutes} : ${seconds} . ${centiseconds}`; 
    } 

    _render() { 
    this.elem.textContent = this._timeFormatter(this.time); 
    } 
} 

ho tutto del tutto all'interno del JSFiddle ho citato sopra ed anche in questo gist se questo è più facile da leggere. Qualsiasi guida sarebbe apprezzata.

+1

Il timer restituirà risultati non corretti quando l'ora del sistema cambia o si verificano secondi bisestili, vedere https://en.wikipedia.org/wiki/Unix_time#Leap_seconds. Meglio usare 'Performance.now()' che aumenta sempre ad un tasso costante. –

risposta

5

Stai parlando di un ritardo di 20 ms, che può essere causato da un certo numero di cose.

  • Come suggerito Flynn1179, là forse da una chiamata al Date.now()
  • setInterval derive di JavaScript! Ed ecco a bin to prove it. Non puoi davvero aspettarti un linguaggio che gira su un singolo thread per pianificare le attività ogni 10 ms con precisione perfetta, e il tuo metodo _update richiede proprio questo.
  • Stai ignorando i 0-9 ms nel contatore dei centisecondi, che viene preso in considerazione nel timer principale. Questo è probabilmente il più grande fattore che contribuisce. Ad esempio, diciamo che il miniwatch A è a 15ms e il miniwatch B è a 15ms. Il Miniwatch A mostrerebbe '01', il miniwatch B mostrerebbe '01', ma l'orologio principale mostrerebbe '03' da 30ms.

per risolvere questo in modo corretto, io consiglierei di ridisegnare la vostra soluzione in modo che si avvolgono tutte le cronometri in un StopwatchManager, che rende tutti i cronometri in una volta e calcola il tempo totale per il vostro orologio principale sommando i tempi di i mini-orologi. Potrebbe anche essere utile esaminare requestAnimationFrame per il rendering anziché setInterval.

+0

Non dimenticare di assegnare la tua ricompensa prima che scompaia per sempre! – fny

+0

Woops, pensavo che fosse già stato dato quando ho accettato una risposta. Ho finito per andare con il tuo approccio di avere il cronometro principale per rendere solo la somma di tutti i tempi dei mini-orologi. Non proprio come volevo, ma almeno funziona bene. Grazie! – saadq

1

Stai arrestando un timer e nella riga successiva, a partire dal successivo. Il tuo problema è parzialmente che il tempo passa tra queste due chiamate di metodo.

Inoltre, il metodo "stop" non utilizza nemmeno l'ora corrente, ma lo interrompe solo retroattivamente dall'ultima volta che è stato aggiornato, non esegue un finale _update.

Se si vuole veramente che si sommano appunto, prendere Date.now() nel metodo updateMiniTimers, e passare che per le chiamate per assicurarsi che essi Stop/Start nello stesso punto nel tempo, e fare un rendering finale dopo una chiamata stop .

In generale, nell'ambito del metodo:

method() { 
    var a = Date.now(); 
    var b = Date.now(); 
} 

A e B non sono assolutamente garantito essere lo stesso, nessun metodo chiamata è istantanea.

+0

Capisco che non è istantaneo, ma non penso che sia necessariamente vero: https://jsfiddle.net/t2go2htL/1/ – saadq

1

Sono d'accordo con Faraz sulle possibili cause. Vorrei anche verificare gli errori di arrotondamento nelle divisioni. Ad ogni modo, se vuoi renderlo un po 'più robusto e scalabile, puoi pensare ai tuoi punti di tempo come elementi in una lista che continua ad espandersi. Ogni volta che si avvia un cronometro, si registra l'indice dell'ultimo elemento nella lista come punto di partenza, ogni volta che si termina si registra l'indice dell'ultimo elemento come punto finale. Ciò consentirebbe di avere gerarchie di timer accurate.

Problemi correlati