バンドルサイズの最適化
Tree Shaking
不要なコードを削除するTree Shakingを効果的に活用します。Copy
// 悪い例:すべてをインポート
import Swiper from 'swiper';
// 良い例:必要なモジュールのみをインポート
import { Navigation, Pagination } from 'swiper/modules';
import Swiper from 'swiper/core';
import 'swiper/css';
動的インポート
必要なタイミングでコードを読み込むことで、初期ロード時間を短縮します。Copy
// 通常のインポート
import { heavyFunction } from './heavy-module';
// 動的インポート
async function loadWhenNeeded() {
const { heavyFunction } = await import('./heavy-module');
heavyFunction();
}
button.addEventListener('click', loadWhenNeeded);
メモリ管理
メモリリーク防止
Copy
class EventManager {
constructor() {
this.handleClick = this.handleClick.bind(this);
document.addEventListener('click', this.handleClick);
}
handleClick() {
// イベント処理
}
// クリーンアップを忘れずに
destroy() {
document.removeEventListener('click', this.handleClick);
}
}
WeakMapとWeakSetの活用
Copy
// メモリリークの可能性あり
const cache = new Map();
// メモリ効率の良い実装
const cache = new WeakMap();
function processUser(user) {
if (cache.has(user)) {
return cache.get(user);
}
const result = expensiveOperation(user);
cache.set(user, result);
return result;
}
DOM操作の最適化
バッチ処理
Copy
// 悪い例:個別のDOM操作
items.forEach(item => {
const div = document.createElement('div');
div.textContent = item;
container.appendChild(div);
});
// 良い例:DocumentFragmentの使用
const fragment = document.createDocumentFragment();
items.forEach(item => {
const div = document.createElement('div');
div.textContent = item;
fragment.appendChild(div);
});
container.appendChild(fragment);
仮想DOM
Copy
// 仮想DOMの基本的な実装例
class VirtualDOM {
static createElement(type, props, ...children) {
return { type, props, children };
}
static render(vnode, container) {
if (typeof vnode === 'string') {
container.appendChild(document.createTextNode(vnode));
return;
}
const element = document.createElement(vnode.type);
Object.entries(vnode.props || {}).forEach(([name, value]) => {
element.setAttribute(name, value);
});
vnode.children.forEach(child => this.render(child, element));
container.appendChild(element);
}
}
イベント処理の最適化
デバウンスとスロットル
Copy
// デバウンス
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// スロットル
function throttle(func, limit) {
let inThrottle;
return function executedFunction(...args) {
if (!inThrottle) {
func(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// 使用例
const optimizedScroll = debounce(() => {
// スクロール処理
}, 250);
window.addEventListener('scroll', optimizedScroll);
非同期処理の最適化
Promise.allとPromise.allSettled
Copy
// 並列実行
async function fetchAllData() {
try {
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments()
]);
return { users, posts, comments };
} catch (error) {
console.error('一つでも失敗すると全体が失敗:', error);
}
}
// エラーハンドリング付き並列実行
async function fetchAllDataSafely() {
const results = await Promise.allSettled([
fetchUsers(),
fetchPosts(),
fetchComments()
]);
return results.map(result => {
if (result.status === 'fulfilled') {
return result.value;
}
console.error('個別のエラー:', result.reason);
return null;
});
}
Web Workersの活用
Copy
// メインスレッド
const worker = new Worker('worker.js');
worker.postMessage({ data: complexData });
worker.onmessage = (event) => {
console.log('処理結果:', event.data);
};
// worker.js
self.onmessage = (event) => {
const result = performHeavyCalculation(event.data);
self.postMessage(result);
};
キャッシュ戦略
メモ化
Copy
function memoize(fn) {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// 使用例
const expensiveFunction = memoize((n) => {
// 重い計算
return n * n;
});
パフォーマンス計測
Copy
// パフォーマンス計測
console.time('処理時間');
// 処理内容
for (let i = 0; i < 1000000; i++) {
// 重い処理
}
console.timeEnd('処理時間');
// メモリ使用量
const used = process.memoryUsage();
console.log(`Memory usage: ${Math.round(used.heapUsed / 1024 / 1024 * 100) / 100} MB`);
パフォーマンス最適化は、実際の測定に基づいて行うことが重要です。
プロファイリングツールを使用して、本当にボトルネックとなっている箇所を特定してください。
過度な最適化は避け、コードの可読性とのバランスを取ることを推奨します。