Menu
CoddyTech

Timers

Part of the Node.js Basics section of Coddy's Node.js journey. Lesson 27 of 33.

A reminder should count down on screen, one step at a time, and then stop.

setInterval(fn, ms) runs fn every ms milliseconds until clearInterval(id) stops it; setTimeout runs once. A program ends only when no timer is left, so an interval you never clear keeps it running.

let lap = 1;
const id = setInterval(() => {
    console.log(`Lap ${lap}`);
    lap += 1;
    if (lap > 3) {
        clearInterval(id);
    }
}, 500);

The terminal stops a program after 5 seconds, which is how you notice a forgotten clearInterval.

challenge icon

Challenge

Easy

A reminder counts down on screen before it shows the note. Add a remind command that does this with a timer.

  1. In notes.js, add a remind command. The word after it is a note number, checked the same way as in done, so you can reuse noteNumber.
  2. Start one setInterval with a delay of 200 milliseconds. Each tick prints one line: first 3, then 2, then 1, then the text of the note.
  3. After printing the note, stop the interval with clearInterval, so the program ends.

With the notes Buy milk and Call Ada, node notes.js remind 2 prints these lines, one every 200 milliseconds:

3
2
1
Call Ada
  1. A number that is not a note fails the way it does in done. With two notes, node notes.js remind 9 prints No note 9 to stderr and exits with code 1, without counting down.

Try it: type remind 1 in the box after $ node notes.js and press Enter. You see the countdown, then your first note. Then type remind 9: you see No note 9 in red and exit code 1. If you forget clearInterval, the program never ends on its own, and the terminal stops it after 5 seconds.

Try it yourself

// Your notes tool starts here.
import { rmSync } from 'node:fs';
import path from 'node:path';
import { formatNote } from './format.js';
import stats from './legacy/stats.cjs';
import store from './store.js';

const [command, ...words] = process.argv.slice(2);
const text = words.join(' ');

const noteNumber = (word) => {
    const n = Number(word);
    if (!Number.isInteger(n) || n < 1 || n > store.notes.length) {
        console.error(`No note ${word}`);
        process.exit(1);
    }
    return n;
};

if (command === 'add') {
    const n = await store.add(text);
    console.log(`Saved note ${n}.`);
} else if (command === 'list') {
    const owner = process.env.NOTES_OWNER ?? 'you';
    console.log(`Notes for ${owner}`);
    if (store.notes.length === 0) {
        console.log('No notes yet');
    }
    const lines = store.notes.map((note, i) => formatNote(i + 1, note));
    if (store.settings.sort === 'newest') {
        lines.reverse();
    }
    lines.forEach((line) => console.log(line));
} else if (command === 'where') {
    const file = path.join(process.cwd(), 'notes.json');
    console.log(file);
    console.log(path.basename(file));
} else if (command === 'stats') {
    console.log(`${store.notes.length} notes, ${stats.countWords(store.notes)} words`);
} else if (command === 'done') {
    const removed = await store.remove(noteNumber(words[0]));
    console.log(`Done: ${removed}`);
} else if (command === 'clear') {
    rmSync('notes.json', { force: true });
    console.log('Deleted notes.json');
} else {
    if (command) {
        console.error(`Unknown command: ${command}`);
    }
    console.error('Usage: node notes.js <command> [words]');
    process.exit(1);
}

All lessons in Node.js Basics

Practice on your own: Express playground