JavaScriptによるシングルスレッドパフォーマンスの最適化方法

JavaScriptによるシングルスレッドパフォーマンスの最適化方法

JavaScriptはシングルスレッドの特性を持つため、コードの効率的な設計が重要です。本記事では、JavaScriptのシングルスレッド環境でパフォーマンスを最適化する具体的な方法を詳しく解説します。

非同期処理の活用

重いタスクを非同期処理にオフロードして、メインスレッドのブロッキングを防ぎます。

setTimeout(() => {
  console.log('非同期処理');
}, 0);
console.log('メインスレッドの処理');

ループの最適化

for文やwhile文を最適化し、無駄な反復処理を排除します。

// 非効率的な例
for (let i = 0; i < array.length; i++) {
  console.log(array[i]);
}

// 効率的な例
for (const item of array) {
  console.log(item);
}

クロージャの適切な使用

クロージャの不要な保持を避けることでメモリリークを防ぎます。

function createCounter() {
  let count = 0;
  return () => {
    count++;
    return count;
  };
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2

デバウンスとスロットリング

頻繁に実行されるイベントリスナーにデバウンスやスロットリングを導入します。

// デバウンスの例
function debounce(func, delay) {
  let timeoutId;
  return function (...args) {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

// スロットリングの例
function throttle(func, limit) {
  let inThrottle;
  return function (...args) {
    if (!inThrottle) {
      func.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

Web Workersの活用

Web Workersでバックグラウンド処理を実現します。

// worker.js
self.onmessage = function (event) {
  const result = event.data * 2;
  postMessage(result);
};

// メインスクリプト
const worker = new Worker('worker.js');
worker.onmessage = function (event) {
  console.log('結果:', event.data);
};
worker.postMessage(10);

リクエストアニメーションフレームの利用

UI更新をスムーズにするために、setTimeoutではなくrequestAnimationFrameを使用します。

function animate() {
  const element = document.getElementById('box');
  let position = 0;

  function step() {
    position++;
    element.style.transform = `translateX(${position}px)`;
    if (position < 100) {
      requestAnimationFrame(step);
    }
  }
  requestAnimationFrame(step);
}

配列メソッドの効率的な使用

map, filter, reduceなどのメソッドを適切に選択します。

// 非効率な例
const result = [];
for (const item of array) {
  if (item > 10) {
    result.push(item * 2);
  }
}

// 効率的な例
const result = array.filter(item => item > 10).map(item => item * 2);

オブジェクトのプロパティアクセスの最適化

頻繁に使用するオブジェクトプロパティは、一時変数にキャッシュします。

const length = array.length;
for (let i = 0; i < length; i++) {
  console.log(array[i]);
}

イベントデリゲーションの使用

多くの要素にイベントリスナーを追加する代わりに、親要素でイベントを処理します。

document.getElementById('parent').addEventListener('click', function (event) {
  if (event.target.matches('.child')) {
    console.log('子要素がクリックされました:', event.target);
  }
});

コード分割によるパフォーマンス改善

モジュールバンドラーでコードを分割し、初期読み込みを最小化します。

// Webpackでのコード分割例
import(/* webpackChunkName: "moduleA" */ './moduleA').then(module => {
  module.default();
});

Lazy Loadingの活用

必要なときにのみリソースを読み込むように設定します。

function loadImage() {
  const img = new Image();
  img.src = 'image.jpg';
  document.body.appendChild(img);
}

タスク分割で応答性を維持

大きなタスクを小さなチャンクに分割して実行します。

function performTask(items) {
  let index = 0;

  function processChunk() {
    const chunk = items.slice(index, index + 100);
    chunk.forEach(item => console.log(item));
    index += 100;

    if (index < items.length) {
      setTimeout(processChunk, 0);
    }
  }
  processChunk();
}

まとめ

JavaScriptのシングルスレッド環境でパフォーマンスを最適化するためには、非同期処理や適切なAPIの活用、効率的なコード設計が重要です。これらのテクニックを実践することで、より高速でスムーズなアプリケーションを実現できます。