Besserer Weg, um Zeit in Millisekunden in Javascript zu bekommen?

141

Gibt es in JavaScript eine Alternative zum Abrufen der Zeit in Millisekunden mithilfe des Datumsobjekts oder zumindest eine Möglichkeit, dieses Objekt wiederzuverwenden, ohne jedes Mal ein neues Objekt instanziieren zu müssen, wenn ich diesen Wert abrufen muss? Ich frage dies, weil ich versuche, eine einfache Spiel-Engine in JavaScript zu erstellen, und wenn ich die "Delta-Frame-Zeit" berechne, muss ich in jedem Frame ein neues Date-Objekt erstellen. Ich bin zwar nicht allzu besorgt über die Auswirkungen auf die Leistung, habe jedoch einige Probleme mit der Zuverlässigkeit der genauen Zeit, die von diesem Objekt zurückgegeben wird.

Ich bekomme jede Sekunde oder so ein seltsames "Springen" in der Animation und bin mir nicht sicher, ob dies mit der Garbage Collection von JavaScript oder einer Einschränkung des Date-Objekts zusammenhängt, wenn ich so schnell aktualisiere. Wenn ich den Delta-Wert auf eine Konstante setze, ist die Animation perfekt glatt, sodass ich ziemlich sicher bin, dass dieses "Springen" mit der Art und Weise zusammenhängt, wie ich die Zeit bekomme.

Der einzige relevante Code, den ich geben kann, ist die Art und Weise, wie ich die Deltazeit berechne:

prevTime = curTime;
curTime = (new Date()).getTime();
deltaTime = curTime - prevTime;

Bei der Berechnung von Bewegung / Animation multipliziere ich einen konstanten Wert mit der Deltazeit.

Wenn es nicht möglich ist, die Zeit in Millisekunden mithilfe des Date-Objekts zu ermitteln, wird eine Funktion verwendet, die eine Variable inkrementiert (dh die seit Beginn des Spiels verstrichene Zeit in Millisekunden) und die mit der SetTimer-Funktion mit einer Geschwindigkeit von aufgerufen wird einmal alle Millisekunden eine effiziente und zuverlässige Alternative sein?

Bearbeiten: Ich habe jetzt meinen Code in verschiedenen Browsern getestet und es scheint, dass dieser "Sprung" wirklich nur in Chrome sichtbar ist, nicht in Firefox. Aber es wäre trotzdem schön, wenn es eine Methode gäbe, die in beiden Browsern funktioniert.

Colin Dumitru
quelle
5
Ein Objekt pro Frame ist nichts
CodesInChaos
2
Könnte dies etwas mit der Tatsache zu tun haben, dass Date.getMillisecondsnur die Millisekunden in der aktuellen Sekunde zurückgegeben werden, dh 0 bis 999? Sie verwenden diese Funktion in Ihrem Beispiel nicht, aber vielleicht wird sie woanders oder in einem anderen Zweig verwendet?
Dan Ross
2
Hat das Springen etwas mit seltsamen Problemen bei der Auflösung von Millisekunden zu tun? Aus den Mozilla-Dokumenten : "Wenn Sie now () zum Erstellen von Zeitstempeln oder eindeutigen IDs verwenden, beachten Sie, dass die Auflösung unter Windows 15 Millisekunden betragen kann." Könnte das mit dem Schluckauf zusammenhängen?
Zashu
1
@zashu das ist schon lange her, daher erinnere ich mich an keine Details für dieses Beispiel. Bei neueren Anwendungen sehe ich bei Verwendung von Date.now () kein Springen mehr.
Colin Dumitru

Antworten:

173

Versuchen Sie Date.now () .

Das Überspringen ist höchstwahrscheinlich auf die Speicherbereinigung zurückzuführen. Normalerweise kann die Speicherbereinigung vermieden werden, indem Variablen so weit wie möglich wiederverwendet werden. Ich kann jedoch nicht genau sagen, mit welchen Methoden Sie die Pausen für die Speicherbereinigung reduzieren können.

Joeri Sebrechts
quelle
1
Ich habe versucht, Date.now () zu verwenden, aber ich habe immer noch die gleichen Sprünge. Jetzt bin ich mir ziemlich sicher, dass es kein Problem mit der Speicherbereinigung ist, sondern eine Einschränkung, wenn genaue Werte mit dem Date-Objekt abgerufen werden. Wie ich bereits sagte, führt das Ersetzen der Deltazeit durch einen konstanten Wert zu reibungslosen Animationen / Übergängen. Die einzige Speicherbereinigung, die möglicherweise stattfindet, ist "neues Datum" oder "Datum.now ()" (wenn diese Funktion ihre eigenen Objekte instanziiert) Ich weiß nicht über).
Colin Dumitru
22
Nur ein Hinweis: Dies funktioniert nicht in IE8 und darunter
Nick
1
Ich mache: / Alles was ich will ist das Datum in ms. Scheint so kompliziert für etwas so Notwendiges.
Damien Golding
5
@Prozi +1 .. IE ist wirklich scheiße, wenn ich Web-Programmierung bin mir IE wirklich egal, nur Chrom und Firefox ..........
TechLife
3
@TechLife Sie sollten auch Android-, Safari- und Opernbrowser überlegen, aber ich stimme zu, dass IE eine Menge Müll ist. Ich meine, es ist so schlimm, dass MS aufgegeben hat und einen neuen Browser in W10
Dendromaniac
49

Ich weiß, dass dies ein ziemlich alter Thread ist, aber um die Dinge auf dem neuesten Stand und relevanter zu halten, können Sie die genauere performance.now()Funktionalität verwenden, um ein feineres Korn-Timing in Javascript zu erzielen.

window.performance = window.performance || {};
performance.now = (function() {
    return performance.now       ||
        performance.mozNow    ||
        performance.msNow     ||
        performance.oNow      ||
        performance.webkitNow ||            
        Date.now  /*none found - fallback to browser default */
})();
Chris GW Green
quelle
2
Die letzte Alternative sollte nur Date.nowanstelle eines anonymen Funktionsausdrucks sein
Bergi
1
Funktioniert leider auch nicht in blöden alten Browsern. Glücklicherweise habe ich meine Kunden überzeugt, mich für die Zeit zu bezahlen, die ich damit verbringe, IE7 und IE8 zu unterstützen.
Michael Scheper
2
|| function () {neues Datum zurückgeben (). getTime ()}
mmm
2
Bemerkenswert ist, dass im performance.now()Gegensatz zu der Zeit von monotone Zeit gibt Date. Dies bedeutet, dass bei jedem nachfolgenden Anruf garantiert ein Wert zurückgegeben wird, der nicht kleiner als der vorherige ist.
Benutzer
48

Soweit ich weiß, kann man mit Date nur Zeit bekommen .

Date.now ist die Lösung, aber nicht überall verfügbar: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/now .

var currentTime = +new Date();

Dies gibt Ihnen die aktuelle Zeit in Millisekunden.

Für deine Sprünge . Wenn Sie Interpolationen gemäß der Delta-Frame-Zeit korrekt berechnen und keinen Rundungszahlenfehler haben , wette ich für den Garbage Collector (GC).

Wenn sich in Ihrer Schleife viele temporäre Objekte befinden, muss die Garbage Collection den Thread sperren, um eine Bereinigung und eine Neuorganisation des Speichers durchzuführen.

Mit Chrome können Sie im Zeitleistenfenster sehen, wie viel Zeit der GC verbringt .

EDIT: Da meine Antwort, Date.now()sollte als die beste Option angesehen werden, da es überall und auf IE> = 9 unterstützt wird.

ngryman
quelle
4
Welche Funktion hat die +dienen +new?
Andrew Scagnelli
33
Die +einfach warf Dateauf Number, einen Standard - Unix - Zeitstempel in Millisekunden zu geben. Sie können diesen Wert explizit erhalten, indem Sie(new Date()).getTime()
ngryman
9
@mikenelson: Nicht schrecklich für mich, das ist offensichtlich, wenn Sie wissen, wie Zwang funktioniert. Das heißt, Date.now()wird jetzt bevorzugt, da seine Unterstützung jetzt groß genug ist.
Ngryman
1
Ich bevorzuge nur +als .getTime()... Es ist einfacher und ich muss mir keine Funktionsnamen merken
2
@TravisJ Tolle Abkürzung? Um einen numerischen Wert abzurufen, der sich bereits in Ihrem Computer befindet, erstellen Sie ein Objekt. Rufen Sie einen Operator auf, der nach einem int testet und eine Konvertierung auslöst, die eine Funktion (valueOf) aufruft, die die Klassenkonvertierungsmethode aufruft, die schließlich eine Funktion (getTime) aufruft Ruft den Wert ab. Dann wird das Objekt seinem Schicksal überlassen, und nach 1000 Iterationen der Schleife haben Sie 1000 gelöschte Datumsobjekte, für die eine Speicherbereinigung erforderlich ist, die plötzlich zusammengelegt werden, und während Ihr Computer hinterherhinkt, fragen Sie sich, was passiert. :) Genial!
FrancescoMM
7

Wenn Sie ein Datumsobjekt wie haben

var date = new Date('2017/12/03');

Dann gibt es eine eingebaute Methode in Javascript, um das Datum im Millisekundenformat abzurufen, das valueOf () ist.

date.valueOf(); //1512239400000 in milliseconds format
Dilip Kumar
quelle
2

Dies ist eine sehr alte Frage - aber immer noch als Referenz, wenn andere sie betrachten - requestAnimationFrame()ist der richtige Weg, um mit Animationen in modernen Browsern umzugehen:

UPDATE: Der Mozilla-Link zeigt, wie das geht - ich hatte keine Lust, den Text hinter dem Link zu wiederholen;)

LarsKnudsen
quelle
4
Willkommen bei Stack Overflow ! Vielleicht möchten Sie eine kurze Erklärung hinzufügen requestAnimationFrame, was dieses "Springen" stoppt, wie in der Frage beschrieben. Vielen Dank!
Qantas 94 Heavy
2
Selbst mit requestAnimationFrame können wir nicht davon ausgehen, dass die Framerate auf allen Plattformen gleich ist. Daher müssen wir immer noch die aktuelle Uhrzeit überprüfen.
Tom Boutell