Erstellen eines Countdown-Timers für Feiertage in JavaScript
Jeden Dezember stehen Entwickler vor derselben Anfrage: einen Countdown bis Weihnachten, Silvester oder einen anderen Feiertag erstellen. Das klingt einfach, bis Ihr Timer um Minuten abweicht, beim Wechseln von Browser-Tabs abbricht oder nach Mitternacht negative Zahlen anzeigt.
Dieser Artikel zeigt Ihnen, wie Sie einen zuverlässigen JavaScript-Countdown-Timer erstellen, der diese Sonderfälle korrekt behandelt. Sie lernen, warum die Neuberechnung der Zeit bei jedem Tick besser ist als das Dekrementieren eines Zählers, wie Sie JavaScript-Zeitzonen korrekt handhaben und wie Sie die häufigsten Fallstricke vermeiden, die die meisten Implementierungen zum Scheitern bringen.
Wichtigste Erkenntnisse
- Berechnen Sie die verbleibende Zeit bei jedem Tick mit
Date.now()neu, anstatt einen Zähler zu dekrementieren, um Timer-Drift zu vermeiden - Verwenden Sie
new Date(year, month, day), um Datumsangaben in der lokalen Zeitzone des Benutzers ohne externe Bibliotheken zu erstellen - Speichern und löschen Sie Intervall-IDs immer, um Speicherlecks zu vermeiden, insbesondere in Single-Page-Anwendungen
- Bauen Sie Resilienz gegen Browser-Tab-Drosselung auf, indem Sie Berechnungen auf tatsächlichen Zeitdifferenzen basieren
Warum dekrementierende Zähler versagen
Der naive Ansatz zum Erstellen eines Holiday-Countdown-JavaScript-Widgets sieht so aus: Setzen Sie eine Variable auf die Anzahl der verbleibenden Sekunden und subtrahieren Sie dann jede Sekunde eins mit setInterval. Das funktioniert in der Praxis nicht.
Das Problem ist setInterval-Timer-Drift. JavaScript-Timer garantieren keine präzise Ausführung. Wenn ein Benutzer Tabs wechselt, drosseln Browser Timer, um Ressourcen zu sparen – manchmal feuern sie einmal pro Sekunde, manchmal einmal pro Minute. Ihr Zähler dekrementiert weiter, als ob die Zeit normal vergangen wäre, aber das ist nicht der Fall.
Die Lösung ist einfach: Berechnen Sie die verbleibende Zeit bei jedem Tick neu, indem Sie Date.now() mit Ihrem Zieldatum vergleichen. Auf diese Weise bleibt die angezeigte Zeit genau, selbst wenn Ihr Timer zu spät feuert.
Einrichten des Zieldatums
Für einen Feiertags-Countdown möchten Sie typischerweise Mitternacht an einem bestimmten Kalenderdatum in der lokalen Zeitzone des Benutzers. So richten Sie das korrekt ein:
function getTargetDate(month, day) {
const now = new Date()
const year = now.getFullYear()
// If the holiday has passed this year, target next year
const target = new Date(year, month - 1, day, 0, 0, 0)
if (target <= now) {
target.setFullYear(year + 1)
}
return target
}
const christmasTarget = getTargetDate(12, 25)
Die Verwendung von new Date(year, month, day) erstellt automatisch ein Datum in der lokalen Zeitzone des Benutzers. Dies behandelt JavaScript-Zeitzonen ohne eine Bibliothek zu benötigen – der Countdown zeigt die Zeit bis Mitternacht am 25. Dezember an, wo auch immer sich der Benutzer befindet.
Hinweis zur Sommerzeit: Das Date-Objekt von JavaScript behandelt Sommerzeitübergänge automatisch, wenn Sie Datumsangaben auf diese Weise erstellen. Der Countdown bleibt genau, selbst wenn die Uhren umgestellt werden.
Die zentrale Countdown-Logik
Hier ist eine produktionsreife Implementierung, die die häufigen Probleme adressiert:
function createCountdown(targetDate, onUpdate, onComplete) {
let intervalId = null
function calculateRemaining() {
const now = Date.now()
const difference = targetDate.getTime() - now
// Prevent negative values
if (difference <= 0) {
clearInterval(intervalId)
onComplete()
return null
}
return {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / (1000 * 60)) % 60),
seconds: Math.floor((difference / 1000) % 60)
}
}
function tick() {
const remaining = calculateRemaining()
if (remaining) {
onUpdate(remaining)
}
}
// Run immediately, then every second
tick()
intervalId = setInterval(tick, 1000)
// Return cleanup function
return () => clearInterval(intervalId)
}
Dieser Ansatz löst mehrere Probleme auf einmal:
- Kein Drift: Die Zeit wird bei jedem Tick frisch neu berechnet
- Keine negativen Werte: Der Countdown stoppt und löscht das Intervall, wenn er abgeschlossen ist
- Ordnungsgemäße Bereinigung: Die zurückgegebene Funktion ermöglicht es Ihnen, den Timer bei Bedarf zu stoppen
- Resilienz gegen Tab-Drosselung: Selbst wenn Ticks verzögert werden, bleibt die angezeigte Zeit korrekt
Discover how at OpenReplay.com.
Verbindung mit dem DOM
Verbinden Sie den Countdown mit Ihrem HTML:
const display = document.getElementById('countdown')
const cleanup = createCountdown(
christmasTarget,
({ days, hours, minutes, seconds }) => {
display.textContent = `${days}d ${hours}h ${minutes}m ${seconds}s`
},
() => {
display.textContent = "It's here!"
}
)
// Call cleanup() when navigating away in a SPA
Behandlung von Sonderfällen
Bereits vergangen: Die Funktion getTargetDate wechselt automatisch zum nächsten Jahr, wenn der Feiertag bereits vergangen ist.
Löschen von Intervallen: Speichern Sie immer die Intervall-ID und löschen Sie sie, wenn der Countdown abgeschlossen ist. Wenn Sie dies nicht tun, entstehen Speicherlecks, insbesondere in Single-Page-Anwendungen.
Barrierefreiheit: Erwägen Sie, aria-live="polite" zu Ihrem Countdown-Container hinzuzufügen, damit Screenreader Updates ankündigen, ohne störend zu sein.
Ausblick
Die kommende Temporal API wird die Handhabung von Datum und Zeit in JavaScript erheblich vereinfachen, mit integrierter expliziter Zeitzonen-Unterstützung. Bis sie in allen Browsern verfügbar ist, bleiben die hier gezeigten Muster die zuverlässige Wahl.
Fazit
Erstellen Sie Ihr Holiday-Countdown-JavaScript-Widget mit Zeitdifferenz-Berechnungen anstelle von dekrementierten Zählern. Ihr Timer bleibt genau, unabhängig von Browser-Drosselung, Tab-Wechseln oder Sommerzeitübergängen – und Sie vermeiden die Debugging-Kopfschmerzen, die einfachere Ansätze verursachen.
FAQs
Browser drosseln JavaScript-Timer in Hintergrund-Tabs, um Ressourcen zu sparen. Wenn Sie einen Zähler jede Sekunde dekrementieren, läuft die Zählung weiter, als ob die Zeit normal vergangen wäre, während der Tab inaktiv war. Berechnen Sie stattdessen die verbleibende Zeit bei jedem Tick neu, indem Sie Date.now() mit Ihrem Zieldatum vergleichen. Dies gewährleistet Genauigkeit, unabhängig davon, wie oft der Timer tatsächlich feuert.
Verwenden Sie den Date-Konstruktor mit numerischen Argumenten wie new Date(year, month, day), um Datumsangaben automatisch in der lokalen Zeitzone des Benutzers zu erstellen. Dieser Ansatz benötigt keine externen Bibliotheken und stellt sicher, dass jeder Benutzer einen Countdown bis Mitternacht in seiner eigenen Zeitzone sieht, anstatt einer festen UTC-Zeit.
Speicherlecks treten auf, wenn setInterval weiterläuft, nachdem der Countdown abgeschlossen ist oder wenn Benutzer in Single-Page-Anwendungen wegnavigieren. Speichern Sie immer die von setInterval zurückgegebene Intervall-ID und rufen Sie clearInterval auf, wenn der Countdown endet oder wenn die Komponente unmountet wird. Geben Sie eine Cleanup-Funktion von Ihrem Countdown-Creator zurück, um eine einfache Entsorgung zu ermöglichen.
Die Temporal API wird die Handhabung von Datum und Zeit mit expliziter Zeitzonen-Unterstützung und klarerer Semantik vereinfachen. Das Kernprinzip der Neuberechnung von Zeitdifferenzen anstelle des Dekrementierens von Zählern bleibt jedoch relevant. Bis Temporal in allen Browsern verfügbar ist, bieten die Muster in diesem Artikel eine zuverlässige browserübergreifende Lösung.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.