JavaScript | 大きな配列を扱うときのパフォーマンス面

JavaScript JavaScript
スポンサーリンク

では次に、Web Worker を使ってプロ仕様サンプルを並列処理化し、UI を止めずに巨大多次元配列を高速に処理する例 を作ります。


例:Web Worker で多次元配列を並列処理(進捗バー+集計付き)

1️⃣ メイン HTML(UI + Worker 起動)

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Web Worker 多次元配列処理デモ</title>
<style>
  #progress {
    width: 100%;
    background-color: #eee;
    border-radius: 5px;
    overflow: hidden;
    margin: 10px 0;
  }
  #bar {
    height: 20px;
    background-color: #3F51B5;
    width: 0%;
  }
  #status { font-family: monospace; }
</style>
</head>
<body>
<h1>Web Worker 多次元配列処理デモ</h1>
<div id="progress"><div id="bar"></div></div>
<p id="status">準備中...</p>

<script>
if (window.Worker) {
  const worker = new Worker('worker.js'); // 別ファイルに処理

  worker.postMessage({ rows: 1000, cols: 1000 }); // データサイズを送信

  worker.onmessage = function(e) {
    const data = e.data;
    if (data.progress !== undefined) {
      document.getElementById('bar').style.width = data.progress + '%';
      document.getElementById('status').textContent =
        `処理中... ${data.progress}% 合計=${data.sum}`;
    }
    if (data.done) {
      document.getElementById('status').textContent =
        `完了! 集計合計 = ${data.sum}, 残り行数 = ${data.remaining}`;
      document.getElementById('bar').style.width = '100%';
    }
  };
} else {
  alert('このブラウザは Web Worker に対応していません。');
}
</script>
</body>
</html>
HTML

2️⃣ Worker ファイル(worker.js)

// worker.js
self.onmessage = function(e) {
  const { rows, cols } = e.data;

  class FastQueue {
    constructor() { this.data = []; this.head = 0; }
    enqueue(v) { this.data.push(v); }
    dequeue() { if (this.head >= this.data.length) return undefined; return this.data[this.head++]; }
    size() { return this.data.length - this.head; }
    compact() { if (this.head > 10000) { this.data = this.data.slice(this.head); this.head = 0; } }
  }

  let queueA = new FastQueue();
  let queueB = new FastQueue();
  for (let i = 0; i < rows; i++) {
    let row = Array.from({length: cols}, (_, j) => j);
    (i % 2 === 0 ? queueA : queueB).enqueue(row);
  }

  const chunk = 10;
  let processed = 0;
  let sum = 0;

  function processChunk() {
    let queues = [queueA, queueB];

    for (let q of queues) {
      let chunkCount = 0;
      while (chunkCount < chunk && q.size() > 0) {
        let row = q.dequeue();

        let newRow = [];
        for (let val of row) {
          if (val % 2 === 0) {
            val = val * 2;
            sum += val;
            newRow.push(val);
          }
        }
        if (newRow.length > 0) q.enqueue(newRow);
        chunkCount++;
      }
      q.compact();
    }

    processed += chunk * queues.length;
    const percent = Math.min(100, Math.floor((processed / rows) * 100));

    self.postMessage({ progress: percent, sum });

    if (processed < rows) {
      setTimeout(processChunk, 0);
    } else {
      self.postMessage({
        done: true,
        sum,
        remaining: queueA.size() + queueB.size()
      });
    }
  }

  processChunk();
};
JavaScript

ポイント解説

  1. UI と処理を完全に分離
    • Worker 内で処理 → メインスレッドがフリーズしない
    • UI は進捗バーやステータス更新に専念できる
  2. 巨大多次元配列も安全
    • 条件付き削除、変換、集計を Worker 内でまとめて実行
    • メインスレッドは負荷なし
  3. 進捗報告
    • postMessage で定期的に進捗を返す
    • チャンク処理 + setTimeout でフリーズ回避
  4. 複数キュー処理
    • queueA / queueB に分けることで並列構造に近い管理
    • 大規模データでも安定

💡 応用例

  • 巨大スプレッドシートのブラウザ上での安全処理
  • ゲームやシミュレーションの並列更新
  • リアルタイム統計・加工の Web アプリ
タイトルとURLをコピーしました