6日目のゴールと今日やること
6日目のテーマは
「複数タイマーを同時に扱える“本格的な時間アプリ”を作る」
ことです。
ここまでであなたは、
ストップウォッチ・カウントダウンのロジックを完全に理解し、
状態管理・多重起動防止・ミリ秒表示まで扱えるようになりました。
6日目はここに、
- 複数タイマーの同時管理
- タイマーごとの状態管理
- setInterval の“複数インスタンス化”
- UI 生成とロジックの分離
- setTimeout を使った「タイマー終了演出」
を加えて、
「タイマーを量産できる設計」を学びます。
複数タイマーを作るための考え方
タイマーは「1つのオブジェクト」として扱う
1つのタイマーは、
次のような情報を持つ“オブジェクト”として扱うと管理しやすくなります。
{
id: 1,
endTime: 0,
remainingMs: 0,
state: "stopped",
timerId: null
}
JavaScriptこれを配列で管理します。
const timers = [];
JavaScript深掘り:タイマーは「状態を持つ小さなアプリ」
1つのタイマーは、
start / pause / resume / reset
という状態遷移を持つ“ミニアプリ”です。
複数タイマーを作るということは、
ミニアプリを複数同時に動かす
ということ。
そのためには、
- タイマーごとに状態を持つ
- タイマーごとに setInterval を持つ
- タイマーごとに UI を持つ
という構造が必要になります。
タイマーを「生成する関数」を作る
タイマーを作る工場(ファクトリー関数)
function createTimer(durationMs) {
return {
id: Date.now() + Math.random(),
endTime: 0,
remainingMs: durationMs,
state: "stopped",
timerId: null
};
}
JavaScriptタイマーを追加する
function addTimer(durationMs) {
const timer = createTimer(durationMs);
timers.push(timer);
renderTimers();
}
JavaScript深掘り:ファクトリー関数は「量産のための仕組み」
1つのタイマーを手作業で作るのではなく、
同じ構造のオブジェクトを量産できる仕組み
を作るのが中級者の発想です。
タイマーごとの「開始 / 停止 / リセット」ロジック
開始処理
function startTimer(timer) {
if (timer.state !== "stopped" && timer.state !== "paused") return;
timer.endTime = Date.now() + timer.remainingMs;
timer.timerId = setInterval(() => {
updateTimer(timer);
}, 10);
timer.state = "running";
renderTimers();
}
JavaScript更新処理
function updateTimer(timer) {
timer.remainingMs = timer.endTime - Date.now();
if (timer.remainingMs <= 0) {
timer.remainingMs = 0;
clearInterval(timer.timerId);
timer.state = "stopped";
renderTimers();
finishEffect(timer);
return;
}
renderTimers();
}
JavaScript停止(pause)
function pauseTimer(timer) {
if (timer.state !== "running") return;
timer.remainingMs = timer.endTime - Date.now();
clearInterval(timer.timerId);
timer.state = "paused";
renderTimers();
}
JavaScriptリセット
function resetTimer(timer) {
clearInterval(timer.timerId);
timer.remainingMs = 0;
timer.state = "stopped";
renderTimers();
}
JavaScript深掘り:タイマーごとに setInterval を持つ
重要なのは、
timer.timerId がタイマーごとに存在する
ということ。
これにより、
- タイマー A は動いている
- タイマー B は停止中
- タイマー C は残り 5 秒
という状態を同時に扱えます。
タイマー UI を「動的に生成」する
タイマーを描画する
function renderTimers() {
const area = document.getElementById("timers");
area.innerHTML = "";
timers.forEach((timer) => {
const div = document.createElement("div");
div.className = "timer";
const timeText = document.createElement("span");
timeText.textContent = formatTime(timer.remainingMs);
const startBtn = document.createElement("button");
startBtn.textContent = "開始";
startBtn.onclick = () => startTimer(timer);
const pauseBtn = document.createElement("button");
pauseBtn.textContent = "停止";
pauseBtn.onclick = () => pauseTimer(timer);
const resetBtn = document.createElement("button");
resetBtn.textContent = "リセット";
resetBtn.onclick = () => resetTimer(timer);
div.appendChild(timeText);
div.appendChild(startBtn);
div.appendChild(pauseBtn);
div.appendChild(resetBtn);
area.appendChild(div);
});
}
JavaScript深掘り:UI は「状態の写し」
UI はあくまで
タイマーオブジェクトの状態を映しているだけ
です。
- タイマーの状態が変わる
- renderTimers() を呼ぶ
- UI が最新状態に更新される
という流れを徹底すると、
複数タイマーでも破綻しません。
setTimeout を使った「終了演出」
タイマー終了時に点滅させる
function finishEffect(timer) {
const element = document.querySelector(`[data-id="${timer.id}"]`);
let count = 6;
function blink() {
element.classList.toggle("blink");
count--;
if (count > 0) {
setTimeout(blink, 200);
}
}
blink();
}
JavaScriptCSS で blink を定義します。
.blink {
background-color: yellow;
}
深掘り:setTimeout の再帰は「回数付きアニメーション」に最適
setInterval では
「6回だけ点滅」
のような制御が難しいですが、
setTimeout の再帰なら
「回数 × 間隔」を自由に作れます。
多重起動防止を「タイマーごと」に行う
タイマーごとに state を持つ
if (timer.state === "running") return;
JavaScriptこれにより、
- タイマー A は連打しても 1 回しか動かない
- タイマー B は別に動かせる
という“独立した動作”が可能になります。
深掘り:状態管理は「複数インスタンス」で真価を発揮する
1つのタイマーなら
isRunning だけで十分ですが、
複数タイマーでは
タイマーごとに状態を持つ
という設計が必須です。
今日いちばん深く理解してほしいこと
6日目の本質は、
- タイマーは「状態を持つオブジェクト」
- タイマーごとに setInterval を持つ
- UI は「状態の写し」
- setTimeout は「演出」に最適
- 多重起動防止は「タイマー単位」で行う
という“複数インスタンス設計”です。
ここまで理解できたあなたは、
もう「タイマーアプリを設計できる人」ではなく、
“タイマーアプリを量産できる人” です。
次の 7日目では、
この複数タイマーをさらに発展させて、
- プリセットタイマー(25分・5分など)
- タイマーの名前付け
- ローカルストレージ保存
- UI の整理と最終仕上げ
を行い、
中級編の集大成に仕上げていきます。

