なぜ「実行時間計測」ユーティリティが業務で効いてくるのか
業務コードを書いていると、
「この処理、なんか重くない?」
「どこがボトルネックなのか分からない」
という場面が必ず出てきます。
ここで大事なのは、
「体感」ではなく「数字」で話せるようにすることです。
この関数は平均 3ms
この API 呼び出しは 250ms
このループは 10,000 件で 120ms
こうやって「実行時間を測る」ことで、
どこを最適化すべきか、どこは放っておいていいか、冷静に判断できるようになります。
そのための小さな道具が「実行時間計測ユーティリティ」です。
いちばん基本の計測:Date.now を使った前後差分
まずは「前後で時刻を取る」だけでいい
一番シンプルな計測は、こうです。
const start = Date.now();
// 計測したい処理
doSomething();
const end = Date.now();
const elapsedMs = end - start;
console.log(`doSomething の実行時間: ${elapsedMs}ms`);
JavaScriptやっていることはとても単純で、
開始前の時刻をミリ秒で取る
終了後の時刻をミリ秒で取る
差を取る
これだけです。
初心者のうちは、まずこの形を「手で書ける」ようになっておけば十分です。
ただし、毎回これを書くのは面倒なので、次のステップとしてユーティリティ化していきます。
同じパターンを何度も書かないための measure 関数
同期処理を計測するユーティリティ
まずは「普通の関数(同期処理)」を計測するユーティリティから。
function measure(fn) {
const start = Date.now();
const result = fn();
const end = Date.now();
const elapsedMs = end - start;
return { result, elapsedMs };
}
JavaScript使い方はこうなります。
function heavyTask() {
let sum = 0;
for (let i = 0; i < 1_000_000; i++) {
sum += i;
}
return sum;
}
const { result, elapsedMs } = measure(heavyTask);
console.log("結果:", result);
console.log("実行時間:", elapsedMs, "ms");
JavaScriptここでの重要ポイントは二つです。
処理の中身(heavyTask)は一切いじらなくていい
「結果」と「実行時間」をセットで返してくれる
つまり、「計測したい処理」をそのまま関数として渡すだけで、
実行時間付きの結果が手に入るようになります。
非同期処理(async / Promise)の実行時間を測る
async 関数用の measureAsync
API 呼び出しなど、業務では非同期処理の計測も必須です。
そのためのユーティリティを用意します。
async function measureAsync(fn) {
const start = Date.now();
const result = await fn();
const end = Date.now();
const elapsedMs = end - start;
return { result, elapsedMs };
}
JavaScript使い方の例です。
async function fetchUser() {
const res = await fetch("/api/user");
return res.json();
}
async function main() {
const { result: user, elapsedMs } = await measureAsync(fetchUser);
console.log("ユーザー:", user);
console.log("API 実行時間:", elapsedMs, "ms");
}
main();
JavaScriptここでの深掘りポイントは、
await fn() の前後で時刻を取っている
非同期処理が終わるまでちゃんと待ってから時間を計測している
ということです。
「Promise を返す処理」を計測したいときは、
必ずこの「measureAsync 版」を使う、という癖をつけておくと混乱しません。
より精度の高い計測:performance.now
Date.now との違いを押さえる
ブラウザ環境では、performance.now() という API があります。
const t1 = performance.now();
// 処理
const t2 = performance.now();
console.log(t2 - t1, "ms");
JavaScriptDate.now() との違いは、
Date.now() は「現在時刻」(1970年からのミリ秒)performance.now() は「ページ読み込みからの経過時間」(小数点以下までの高精度)
という点です。
細かい差ですが、
「短い処理の計測」「パフォーマンスチューニング」では performance.now() の方が向いています。
同じ measure を performance.now で書き直すとこうなります。
function measureHighRes(fn) {
const start = performance.now();
const result = fn();
const end = performance.now();
const elapsedMs = end - start;
return { result, elapsedMs };
}
JavaScript「まずは Date.now で十分」「本気でチューニングするときに performance.now を使う」
くらいの感覚で覚えておけば OK です。
ログ出力まで含めた「計測+ログ」ユーティリティ
名前付きで計測すると後から見やすい
実務では、「どの処理を測ったのか」がログから分かることが大事です。
そこで、処理名を受け取るユーティリティにしておくと便利です。
function measureWithLog(label, fn) {
const start = Date.now();
const result = fn();
const end = Date.now();
const elapsedMs = end - start;
console.log(`[measure] ${label}: ${elapsedMs}ms`);
return result;
}
JavaScript使い方はこうです。
function calc() {
let x = 0;
for (let i = 0; i < 500_000; i++) {
x += i;
}
return x;
}
const value = measureWithLog("calc 処理", calc);
JavaScriptログにはこう出ます。
[measure] calc 処理: 37ms
これだけで、「どの処理がどのくらい時間を食っているか」を
ざっくり把握するのがかなり楽になります。
非同期版も同じノリで書けます。
async function measureAsyncWithLog(label, fn) {
const start = Date.now();
const result = await fn();
const end = Date.now();
const elapsedMs = end - start;
console.log(`[measure] ${label}: ${elapsedMs}ms`);
return result;
}
JavaScript実務での具体的な利用イメージ
API 呼び出しの「体感」と「実測」を揃える
「この画面、なんか遅いんだよね」というとき、
どの API がどのくらい遅いのかを測るのはとても有効です。
async function loadPage() {
const user = await measureAsyncWithLog("ユーザー取得", () =>
fetch("/api/user").then((r) => r.json())
);
const orders = await measureAsyncWithLog("注文一覧取得", () =>
fetch("/api/orders").then((r) => r.json())
);
render({ user, orders });
}
JavaScriptログを見れば、
ユーザー取得: 80ms
注文一覧取得: 450ms
のように、「どこが重いか」が一目で分かります。
重いループや処理のボトルネック探し
例えば、「この集計処理が重い」と感じたとき、
処理の中を細かく分けて計測することもできます。
function aggregate(data) {
const step1 = measureWithLog("フィルタリング", () => {
return data.filter((x) => x.active);
});
const step2 = measureWithLog("ソート", () => {
return [...step1].sort((a, b) => a.value - b.value);
});
const result = measureWithLog("集計", () => {
return step2.reduce((sum, item) => sum + item.value, 0);
});
return result;
}
JavaScriptこれで、「フィルタリングが重いのか」「ソートが重いのか」「集計が重いのか」が数字で見えます。
最適化の優先順位がはっきりします。
小さな練習で感覚をつかむ
次のようなことを自分で試してみると、実行時間計測の感覚がつかみやすいです。
同じ処理を「1000 件」「1 万件」「10 万件」で実行して、
それぞれの実行時間を measure で測ってみる
配列の for、forEach、map などで同じ処理を書いて、
どのくらい時間が違うかを比べてみる
ここで大事なのは、
「速い/遅いを感覚で語らない」
「必ず数字で確認する」
という習慣をつけることです。
実行時間計測ユーティリティは、その習慣を支えるための小さな道具です。
一度自分のプロジェクトに組み込んでしまえば、
「なんか遅いな」と感じたときに、すぐに数字を取りに行けるようになります。
