JavaScript/Tutorials/Timer und Countdown
Hast du jemals einen Countdown-Timer für ein Projekt benötigt? Eine Suche im Netz findet viele Bibliotheken - eine Lösung mit Vanilla-JS ist aber gar nicht so schwierig.
In diesem Tutorial lernst Du, wie man einen Timer baut, der die Zeit hoch- oder bei einem Countdown herunterzählt. Dabei verwenden wir neben JavaScript HTML, SVG und gestalten alles mit CSS. Deshalb solltest Du bereits Grundkenntnisse in diesen Technologien vorweisen können.
Information
2009 wurde mit ES5 Date.now() eingeführt, das unser Timer-Script radikal vereinfacht.
Inhaltsverzeichnis
Vorüberlegungen
JavaScript-Programme sind nicht mit anderen Computerprogrammen zu vergleichen, die eine bestimmten Startzeit und Endzeit ihrer Ausführung haben. JavaScripte werden immer wieder für kurze Zeit aktiv, etwa wenn auf Ereignisse reagiert wird. Wenn ein JavaScript tatsächlich mehrere Sekunden an einem Stück läuft und die gesamten Rechenkapazitäten in Beschlag nimmt, friert der Browser ein oder zeigt einen Dialog, mit dem das Script abgebrochen werden kann.
Dementsprechend gibt es in JavaScript keinen Befehl sleep
, der einfach für eine gegebene Zeit nichts tut. So etwas ist in JavaScript nicht möglich. Allerdings lassen sich über window.setTimeout und window.setInterval Funktionen nach einer angegebenen Wartezeit aufrufen.
Soll ein Script über längere Zeit laufen und zwischen einzelnen Befehlen eine Wartezeit verstreichen lassen, ist dies in JavaScript nur mit window.setTimeout über das »Stop & Go«-Verfahren möglich. Auf diese Weise können z.B. Animationen umgesetzt werden.
Ein verzögerter Aufruf sieht in manch anderen Sprachen schematisch so aus:
befehl1;
sleep(5);
befehl2;
In JavaScript hingegen notieren wir eine Funktion, die wir zeitverzögert aufrufen:
befehl1;
function befehl2 () {}
window.setTimeout(befehl2, 5000);
Knifflig wird es nun, wenn ein Befehl mit sich ändernden Parametern mehrmals ausgeführt werden soll und dazwischen jeweils eine Zeitspanne liegen soll. Ein Countdown etwa ließe sich in anderen Sprachen schematisch so realisieren:
for ($i = 10; $i > 0; i--) {
echo $i . "\n";
sleep(1);
}
In JavaScript wird dies üblicherweise mit einer Funktion gelöst, die sich immer wieder selbst verzögert aufruft und dabei den Schleifenzähler übergibt:
function countdown (i) {
if (i == undefined) {
// Startwert
i = 10;
}
alert(i);
if (i > 0) {
i--;
// Funktion verzögert aufrufen
var timeout = window.setTimeout('countdown(' + i + ')', 1000);
}
}
// Countdown anstoßen
countdown();
Wir sehen hier bereits, wie kompliziert die Umsetzung eines einfachen Countdowns wird. Diese verbreitete Umsetzung lässt sich zunächst durch den Einsatz von Closures vereinfachen. Damit lässt sich die Übergabe von Parametern einfacher gestalten: Anstatt window.setTimeout("countdown(" + i + ")", 1000);
können wir ebenso eine anonyme Funktion notieren, die als Closure wirkt und in der die lokale Variable i
zur Verfügung steht: window.setTimeout(function () { countdown(i) }, 1000);
. Dies ist vor allem sinnvoll, wenn mehr und komplexere Variablen übergeben werden müssen, die nicht so einfach in einen String linearisiert werden können.
Wenn mehrere Funktionen periodisch aufgerufen werden sollen, so ist es umständlich, denselben Mechanismus immer wieder neu zu notieren. Im Folgenden wird eine Helferfunktion vorgestellt, mit der sich solche Aufgaben komfortabel umsetzen lassen.
Vorstellung der Timer-Methode
Timer mit Date.now()
Die Methode setInterval ist eigentlich dafür prädestiniert, eine Zeit entweder herauf-, oder bei einem Countdown herunterzuzählen. Da JavaScript single-threaded ist, kann es aber bei der Ausführung von Skripten zu kleineren Verzögerungen kommen, sodass solche Timer nie sekundengenau funktionieren.
Mit date.now() kannst du einen solchen Timer problemlos takten:
function timer() {
const startTime = Date.now();
let interval = setInterval(function() {
let elapsedTime = Date.now() - startTime;
document.getElementById('timer').textContent = (elapsedTime / 1000).toFixed(1);
}, 100);
}
In dieser timer
-Funktion wird anfangs ein Startzeitpunkt mit Date.now()
festgelegt und der Variablen startTime
zugewiesen.
Mit setInterval wird nun in einer anynomen Funktion der aktuelle Zeitpunkt ermittelt und um den Startzeitpunkt vermindert.
Diese elapsedTime
wird bei der Ausgabe entsprechend formatiert:
- mit einer Division durch 1000 erhält man die Sekunden,
- mit toFixed wird die Anzahl Nachkommastellen passend abgeschnitten, sodass nur Zehntelsekunden sichtbar sind.
Countdown - rückwärts zählen
Natürlich kann man mit JavaScript auch rückwärts zählen:
const count = 15;
const timer = setInterval(function() {
count--;
console.log(count);
if (count === 0) {
clearInterval(timer);
console.log("Countdown finished!");
}
}, 1000);
In seiner einfachsten Variante verzichten wir auf das Date-Objekt und überlassen das Zählen der setInterval()-Methode, deren zweiter Parameter die Angabe 1000
(Millisekunden) erhält und die so jede Sekunde die Zählvariable count
einmal mit -- um eins verringert und dann ausgibt.
Wenn count
0 beträgt, wird mit clearInterval das Intervall gelöscht und eine Meldung ausgegeben.
Als Modifikation unseres ersten Beispiels
const duration = 15;
function timer(duration) {
const startTime = Date.now();
const targetTime = startTime + (duration * 1000); // Convert seconds to milliseconds
let interval = setInterval(function() {
let elapsedTime = targetTime - Date.now();
if (elapsedTime > 0) {
document.getElementById('timer').textContent = (elapsedTime / 1000).toFixed(1);
} else {
clearInterval(interval);
document.getElementById('timer').textContent = "0.0";
console.log("Countdown finished!");
}
}, 100);
}
ToDo (weitere ToDos)
siehe Forum: SELF-Wiki: Zeit & Datum
Bereits bestehende Seiten:
- CSS/Custom_properties_(CSS-Variablen)#Countdown
- JavaScript/WindowOrWorkerGlobalScope/setTimeout#Countdown mit Start und Stop
Visualisierung mit CSS-Animation
Analog oder digital?
Mit SVG kannst du auch das Zifferblatt einer Uhr und Zeiger darstellen:
Ausführungszeiten messen
Wenn du Lade- und Laufzeiten von Skripten messen und vergleichen willst, reicht das Date-Objekt von JavaScript nicht aus, da die Systemzeit des Anwenderrechners nicht hinreichend genau ist. Theoretisch misst sie in Millisekunden – praktisch verzögert sich die Ausführung von Skripten durch die single-threaded Natur von JavaScript. Darüber hinaus wird die Systemzeit alle 15-20 Minuten synchronisiert, sodass es hier zu Sprüngen von mehreren Millisekunden kommen kann.
var start = new Date();
// CODE, der gemessen werden soll
var time = new Date() - start;
// time is the number of milliseconds it takes to execute the script
High Resolution Time
Der DOMHighResTimeStamp kann zum Speichern von Zeitwerten verwendet werden. Im Unterschied zum Date-Objekt kann es dabei bis zu 5/1000 einer Millisekunde (5 µs (Microsekunden)) unterscheiden.[2]
performance.now()
Die Methode window.performance.now
ermöglicht ähnlich wie Date.now() das Messen und Vergleichen von Zeitpunkten. Dabei bietet es aber timestamps mit einer kleineren Auflösung als die im Date-Objekt verwendeten Millisekunden, um die Seitenperformance messen zu können.[3]
Grundlage ist nicht der 01.01.1970, sondern die in performance.timing.navigationStart
gespeicherte Zeit, in der die fragliche Seite geladen wurde.
var start = performance.now();
// CODE, der gemessen werden soll
var time = performance.now();
console.log('Dauer: ' + (time - start) + ' ms.');
Online-Testlabore
Ausführungszeiten selbst zu messen ist dann nötig, wenn man eine solche Messung im echten Code braucht. Um die Performance von unterschiedlichen Implementierungen eines Algorithmus zu testen, gibt es Tools, die dabei unterstützen.
Eines davon ist [1], das die Laufzeit von Codesnippets misst und vergleicht. Es basiert auf [2], womit Sie auch ihre eigene Benchmark-Suite erstellen können.
Wir möchten damit nicht sagen, dass dieses Tool das einzige oder das beste ist. Es funktioniert, macht keine Werbung und setzt keine Third-Party Cookies (Stand November 2024). Weitere Vorschläge für solche Tools nehmen wir gerne entgegen.
Siehe auch
- Einführung in Zeit & Datum
- Monatskalender
- input type="date" und mehrHTML5 bietet eine Vielzahl von neuen Eingabe-Typen für Datums- und Zeitangaben.
Weblinks
- ↑ Dies ist eine umfassende Neubearbeitung des SELFHTML-aktuell-Artikels Komfortable Timer-Funktion - ein Helferscript zum wiederholten Ausführen von Funktionen.
Das Script wurde im Zusammenhang mit einer Forumsdiskussion von Struppi entwickelt und von Mathias Schäfer dokumentiert.
2009 wurde mit ES5 Date.now() eingeführt, das unser Timer-Script radikal vereinfacht. - ↑ W3C: High Resolution Time
- ↑
MDN: Performance.now()
- developers.google: When milliseconds are not enough: performance.now von Paul Irish
- John Resig: Accuracy of JavaScript Time