以下の内容はhttps://blog.cateiru.com/entry/2026/01/06/105407より取得しました。


iframe を再帰的に表示させてフィボナッチ数を計算する

Note

この記事は はてなエンジニア Advent Calendar 2025 の1月6日の記事です。はてなでは、アドベントカレンダーはクリスマス以降も続きます。

developer.hatenastaff.com

はじめに

iframe 使っていますか? iframe というのは HTML の要素の一つで現在のページに別のページを埋め込むことがきるものです。

developer.mozilla.org

iframe の歴史は長く、正式な仕様としては HTML4.0 から標準化されています。現在でも埋め込み広告だったり、ブログなどでは YouTube や X の埋め込み表示などに使われていて現在の Web でも無くてはならない存在となっています。

www.w3.org

そんな iframe ですが、以下のような特徴があります。

  1. 理論上無限にネストができる
  2. プロセスが独立している
  3. 親と通信するには postMessage などを使う必要がある

つまり、プログラミング言語でいう「関数」と似たようなことができるということです(?)

このエントリではそんな iframe を使って再帰関数を擬似的に再現してフィボナッチ数を求めるプログラムを作っていきます。

Tip

作ったものは GitHub - cateiru/iframe-recursion-poc に置いています。MITライセンス下でご自由にお遊びください。

また、GitHub Pages にもデプロイしました。以下から試すことができます。

cateiru.github.io

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-1n-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 にもデプロイしました。以下から試すことができます。

cateiru.github.io

Caution 再掲

iframe を動的に表示するため、計算するフィボナッチ数の値を高くすると高負荷になります。11以上を計算する際にはブラウザクラッシュにお気をつけください。

デモでは、フォームに計算したフィボナッチ数の n の値を入力することでその値に対応するフィボナッチ数を得ることができます。

フォームに8と入力して「計算する」ボタンを押すと右側で iframe が再帰的に表示される。その後、「Result for n=8: 21, computed in 2244.10 ms」という結果が得られる
デモの動作例、8を入力すると21が返ることがわかる

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 は色々なテクい使い方ができることを覚えておくと今後役に立つかも知れません。特に、プロセスが分離されているので以下のような使い方などはプロダクトや業務で使うときが来るかも知れません。

他にも iframe には面白い機能が盛りだくさんなので是非遊んでみてください!!

*1:メモ化などは一旦考えません

*2:趣味です




以上の内容はhttps://blog.cateiru.com/entry/2026/01/06/105407より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14