ブラウザでsetIntervalの負荷計測を行ってみる
はじめに
setInterval
は一定の間隔を置いて関数やコードスニペットを繰り返し呼び出すために利用するもので、React等のコンポーネント内で呼び出した際は コンポーネントの廃棄時に同時に clearInterval
等で停止させる事が理想とされています。
これは、コンポーネントが表示されなくなった後も バックグラウンドで定期実行が行なわれてしまうので、意図しない挙動をしたり ブラウザの負荷に繋がる事が理由とされています。
今回は 実際にsetIntervalを実行した際にブラウザでどれくらいの負荷になっているのかをChromeのDevtoolsから確認してみます。
setIntervalを実行してみる
setIntervalを実行するreactコンポーネントを用意しました。
import { useState } from "react";
export const TimerSwitch = () => {
const [elements, setElements] = useState([]);
const handleIntervalOn = () => {
setInterval(() => {
setElements((prevElements) => {
const newElements = [...prevElements];
newElements.push(new Date().toLocaleTimeString());
return newElements;
}
);
}
, 1000);
}
return (
<div>
<button onClick={handleIntervalOn}>
タイマーオン
</button>
{
elements.map((element, index) => (
<div key={index}>
{element}
</div>
))
}
</div>
);
}
表示としては
こんな感じで
上部のボタンを押す度にsetIntervalが実行され、1000ms毎に 現在時刻が下に追加されるようになっています。
setIntervalの廃棄処理を行なっていないので 連打とかをすると、タイマーが重複して追加されるので大量の時刻表示が高速で追加されるようになっています。
計測を行う
ChromeのDevtoolを開き、Performのタブを開きます。
Performタブ右上の丸いRECアイコンをクリックし、計測をはじめます。
画面を操作しないまま放置し、10秒くらい待った後にintervalのタイマーオンのボタンを連打してみました。20秒経過したくらいでPerformタブ内のStopを押して、計測を停止します。
計測を見る
結果はこんな感じになりました。
10000ms経過時点から、タイムライン内の表示が急に増えています。
これがintervalの実行によるものなのでしょうか。
interval
で検索をかけると、ヒットした場所が黄色くハイライトされます。
やはり、10000msあたりで増えているマーカーがintervalの実行タイミングで間違い無いようです。
予期しないintervalが負荷の原因か調べる際は、こんな感じで実行のタイミングを確認するのが良さそうです。
どれくらいの負荷になっているかもついでに調べます。
import { useRef, useState } from "react";
export const TimerSwitch = () => {
const [elements, setElements] = useState([]);
const intervalRefs = useRef([]);
const handleIntervalOn = () => {
const id = setInterval(() => {
setElements((prevElements) => {
const newElements = [...prevElements];
newElements.push(new Date().toLocaleTimeString());
return newElements;
}
);
}, 1000);
intervalRefs.current.push(id);
}
+ const handleClearInterval = () => {
+ intervalRefs.current.forEach((id) => {
+ clearInterval(id);
+ });
+ intervalRefs.current = [];
+ }
return (
<div>
<button onClick={handleIntervalOn}>
タイマーオン
</button>
+ <button onClick={handleClearInterval}>
+ タイマークリア
+ </button>
{
elements.map((element, index) => (
<div key={index}>
{element}
</div>
))
}
</div>
);
}
実行中のintervalを全てクリアするボタンを追加しました。
Memoryタブを開きます。
タイマーオンを一回クリックしてsetIntevalを実行し、RECアイコンのボタンを押します。
Timer
でSortをかけて現在実行している(メモリを占有している)タイマーを確認してみました。
Shallow Size
がタイマー自体の占有率ですので、0.2KBという事がわかりました。
タイマーをクリア後はソートにひっかかりません。メモリが開放されている(使われていない)事がわかります。

株式会社SKIYAKIのテックブログです。ファンクラブプラットフォームBitfanの開発・運用にまつわる知見や調べたことなどを発信します。主な技術スタックは Ruby on Rails / React / AWS / Swift / Kotlin などです。 recruit.skiyaki.com/
Discussion