-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
193: Building a Real-Time Clock and Alarm App
When I first started building timers and clocks, I fell into a trap that I still see developers stumble into today: the belief that to make something "real-time," you need to create a loop that runs as fast as possible to "catch" the exact millisecond a second changes. You might be tempted to write a while(true) loop or a recursive setTimeout that fires every 10 milliseconds just to be "precise."
The "Infinite Loop" Trap and Why It Freezes Your Browser
Let's look at why that's a disaster. If you try to do something like this:
while (true) {
console.log(new Date().toLocaleTimeString());
}
Your browser tab will instantly freeze. You won't see a clock ticking; you'll see a "Page Unresponsive" warning. Because JavaScript is single-threaded, that while loop hogs the entire execution thread. The browser can't paint the UI, it can't handle clicks, and it certainly can't update the text on your screen. You're essentially telling the browser, "Ignore everything in the universe except this loop."
Letting the Browser Breathe with setInterval
The trick to a real-time clock isn't about high-frequency polling; it's about scheduling. We don't need to track every millisecond; we just need the UI to refresh enough that the human eye sees a consistent update. I always recommend setInterval for this. It tells the browser: "Go do other things, and every 1,000 milliseconds, come back and run this specific bit of code."
Here is the core logic I use for a basic ticker:
const clockElement = document.getElementById('clock');
setInterval(() => {
const now = new Date();
clockElement.innerText = now.toLocaleTimeString();
}, 1000);
Notice I'm calling new Date() inside the interval. A common rookie mistake is defining the date once outside the loop and then just trying to increment a variable. Don't do that. Let the system clock be your source of truth; it's far more accurate than any counter you'll build manually.
Matching the Alarm to the System String
Adding an alarm sounds complex, but it's actually just a string comparison problem. If you're building a simple alarm app, you don't need complex timestamp math. You just need to know if the "current time string" matches the "alarm time string."
I personally find it easiest to store the alarm time in a format that matches toLocaleTimeString() or a simple HH:MM format. Every time the clock ticks, we run a check:
let alarmTime = "14:30:00"; // Set by user input
setInterval(() => {
const now = new Date();
const currentTime = now.toLocaleTimeString();
document.getElementById('clock').innerText = currentTime;
if (currentTime === alarmTime) {
alert("Time to wake up!");
}
}, 1000);
It's simple, it's clean, and it doesn't kill the CPU. One detail to watch out for: toLocaleTimeString() can vary based on the user's locale (some use 12-hour, some 24-hour). In a production app, I'd suggest using a library like Day.js or manually formatting the hours and minutes to ensure the comparison doesn't fail just because the user is in London instead of New York.
Preventing the "Alarm Spam" Effect
If you use the code above, you might notice that the alarm triggers multiple times within that one second if the browser's timing is slightly off, or it might trigger and then immediately trigger again. To fix this, I always implement a "triggered" flag. This ensures the alarm only goes off once per scheduled minute.
let alarmActive = false;
// Inside the interval...
if (currentTime === alarmTime && !alarmActive) {
triggerAlarm();
alarmActive = true;
}
if (currentTime !== alarmTime) {
alarmActive = false; // Reset the flag once the second passes
}
This little boolean toggle is the difference between a professional tool and an app that crashes the browser with a hundred alert boxes.
📋 Practical Task
Implementing a "Time-Until-Alarm" Countdown Timer
Modify the clock and alarm logic from this lesson to include a live countdown. Instead of only showing the current time, add a second display element that tells the user exactly how many hours, minutes, and seconds remain until the alarm triggers.
- Create an input field where the user can set the alarm time (e.g., "15:30").
- Calculate the difference between the current system time and the alarm time.
- Update a
<div id="countdown">every second to show the remaining time (e.g., "02:15:10 remaining"). - Ensure that once the alarm is reached, the countdown displays "Alarm Triggered!" instead of negative numbers.
There are no comments for now.