Note
この記事は はてなエンジニア Advent Calendar 2025 の1月6日の記事です。はてなでは、アドベントカレンダーはクリスマス以降も続きます。
はじめに
iframe 使っていますか? iframe というのは HTML の要素の一つで現在のページに別のページを埋め込むことがきるものです。
iframe の歴史は長く、正式な仕様としては HTML4.0 から標準化されています。現在でも埋め込み広告だったり、ブログなどでは YouTube や X の埋め込み表示などに使われていて現在の Web でも無くてはならない存在となっています。
そんな iframe ですが、以下のような特徴があります。
- 理論上無限にネストができる
- プロセスが独立している
- 親と通信するには postMessage などを使う必要がある
つまり、プログラミング言語でいう「関数」と似たようなことができるということです(?)
このエントリではそんな iframe を使って再帰関数を擬似的に再現してフィボナッチ数を求めるプログラムを作っていきます。
Tip
作ったものは GitHub - cateiru/iframe-recursion-poc に置いています。MITライセンス下でご自由にお遊びください。
また、GitHub Pages にもデプロイしました。以下から試すことができます。
Caution
iframe を動的に表示するため、計算するフィボナッチ数の値を高くすると高負荷になります。11以上を計算する際にはブラウザクラッシュにお気をつけください。
技術的解説
まず、フィボナッチ数とはなにかについて説明していきます。フィボナッチ数とは 2, 3, 5, 8, 13… のように前の数を足した値が続く数列のことです。そして、このフィボナッチ数を計算するプログラムはよく再帰関数の例題で出されることが多いです。
n のフィボナッチ数を求める場合、再帰関数を使用すると以下のように書くことができます*1。
function fib(n) { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); }
この関数と同じことを iframe でやるというわけです。
iframe と親との通信
iframe は独立したプロセスであるため、JavaScript の実行プロセスも分離されています。そのため情報の伝達にコツが要ります。今回は双方向で通信したいため postMessage を使います。
親から子(iframe)に通信する場合は、
iframeElement.contentWindow.postMessage([object Object], "*");
のようにすることで送信できます。逆に子から親に通信する場合は、
window.parent.postMessage([object Object], "*");
とすることで送信可能です。受信側は message イベントをリッスンすることで受け取ることができます。
今回は iframe 内で 2つの iframe を起動し、n-1 と n-2 の計算を委任、返ってきた値の和を親に送信するようにしました。
window.addEventListener("message", (event) => { if (event.data.type === "compute") { const n: number = event.data.n; if (n <= 1) { // 1以下ならそのまま返す window.parent.postMessage({ type: "result", n, result: n }, "*"); return; } let result1: number | null = null; let result2: number | null = null; const handleMessage = (e: MessageEvent) => { if (e.data.type === "result") { const resN: number = e.data.n; const resResult: number = e.data.result ?? resN; // ここで受信した値を保持する if (resN === n - 1) { result1 = resResult; } else if (resN === n - 2) { result2 = resResult; } // 両方の結果が揃ったら合計を計算して親に送信 if (result1 !== null && result2 !== null) { const total = result1 + result2; window.parent.postMessage( { type: "result", n, result: total }, "*" ); // イベントリスナーを削除 window.removeEventListener("message", handleMessage); } } }; // メッセージイベントリスナーを追加 window.addEventListener("message", handleMessage); // 再帰的に計算を依頼 iframeElement1.onload = () => { iframeElement1.contentWindow?.postMessage( { type: "compute", n: n - 1 }, "*" ); }; iframeElement2.onload = () => { iframeElement2.contentWindow?.postMessage( { type: "compute", n: n - 2 }, "*" ); }; } });
iframeの再帰制限
実は、iframe には再帰を制限する機能が存在します。同じURLで iframe を開こうとするとブラウザは自己参照と解釈して意図的に about:blank になります。これでは、フィボナッチ数の計算ができません。
そのため、回避策としてクエリパラメータを付与して別のページと認識します。
const u = new URL(location.href); u.pathname = "/iframe-recursion-poc/recursion"; u.searchParams.set("n", n.toString()); // ここでクエリパラメータを付与している const iframeElement1 = document.createElement("iframe"); iframeElement1.src = u.toString(); const iframeElement2 = document.createElement("iframe"); iframeElement2.src = u.toString(); // iframe をコンテナに追加 iframeContainerElement?.appendChild(iframeElement1); iframeContainerElement?.appendChild(iframeElement2);
デモ
Tip 再掲
作ったものは GitHub - cateiru/iframe-recursion-poc に置いています。MITライセンス下でご自由にお遊びください。
また、GitHub Pages にもデプロイしました。以下から試すことができます。
Caution 再掲
iframe を動的に表示するため、計算するフィボナッチ数の値を高くすると高負荷になります。11以上を計算する際にはブラウザクラッシュにお気をつけください。
デモでは、フォームに計算したフィボナッチ数の n の値を入力することでその値に対応するフィボナッチ数を得ることができます。

n とフィボナッチ数の対応は以下のようになっています。正しい値になっていることが確認できるかと思います。
| n | フィボナッチ数 F(n) |
|---|---|
| 0 | 0 |
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 5 |
| 6 | 8 |
| 7 | 13 |
| 8 | 21 |
| 9 | 34 |
| 10 | 55 |
また、表示する iframe は毎回背景色を動的に出すようにしているためなんとなく見ていて楽しくなっています*2。
実行時間の課題
デモを作ってみた感じ、問題無く計算はできるようですがやはり実行時間は遅いです。動的に iframe を組み立てているのでそれはそうという感想ですが、 n=10 を計算するのにPCなら大体11秒前後、スマホなどで計算すると2、30秒ほどかかってしまいそうです。
というのも、iframe を表示するロジックは並列ではないっぽいというのを Network タブから眺めていました。まあ、ブラウザ次第なのではとは思っています。
まとめ
いかがだったでしょうか?こんな知識いつ使うんだ!と思うかも知れませんが、 iframe は色々なテクい使い方ができることを覚えておくと今後役に立つかも知れません。特に、プロセスが分離されているので以下のような使い方などはプロダクトや業務で使うときが来るかも知れません。
- ServiceWorker や WebWorker の代替として使う
- レンダリングした結果の計算を行う
- ePub ビューワである Bibi | EPUB Reader on your website. — ビビ。EPUB リーダを、あなたのウェブサイトに。 ではページ数計算のために iframe を使用してるようです。
- 並列計算用途として使う
- ベンチマークツールとして使う
他にも iframe には面白い機能が盛りだくさんなので是非遊んでみてください!!