JavaScript Performance Cheatsheet
Performance API
const start = performance.now();
expensiveOperation();
const end = performance.now();
console.log(`Operation took ${end - start} milliseconds`);
performance.mark('fetchStart');
fetch('/api/data').then(() => {
performance.mark('fetchEnd');
performance.measure('fetch', 'fetchStart', 'fetchEnd');
const measure = performance.getEntriesByName('fetch')[0];
console.log(`Fetch took ${measure.duration}ms`);
});
const memUsage = process.memoryUsage();
console.log('Memory usage:', {
rss: `${Math.round(memUsage.rss / 1024 / 1024)} MB`,
heapTotal: `${Math.round(memUsage.heapTotal / 1024 / 1024)} MB`,
heapUsed: `${Math.round(memUsage.heapUsed / 1024 / 1024)} MB`
});
if ('memory' in performance) {
console.log('Memory info:', {
used: Math.round(performance.memory.usedJSHeapSize / 1024 / 1024),
total: Math.round(performance.memory.totalJSHeapSize / 1024 / 1024),
limit: Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024)
});
}
Benchmarking
function benchmark(fn, iterations = 1000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
return (end - start) / iterations;
}
const time1 = benchmark(() => arrayMethod1());
const time2 = benchmark(() => arrayMethod2());
console.log(`Method 1: ${time1.toFixed(4)}ms per iteration`);
console.log(`Method 2: ${time2.toFixed(4)}ms per iteration`);
function benchmarkWithWarmup(fn, iterations = 1000, warmup = 100) {
for (let i = 0; i < warmup; i++) {
fn();
}
return benchmark(fn, iterations);
}
function memoryBenchmark(fn) {
const memBefore = process.memoryUsage().heapUsed;
fn();
const memAfter = process.memoryUsage().heapUsed;
return memAfter - memBefore;
}
Performance Monitoring
const performanceMetrics = {
operations: 0,
totalTime: 0,
maxTime: 0,
minTime: Infinity
};
function trackPerformance(operation) {
const start = performance.now();
const result = operation();
const duration = performance.now() - start;
performanceMetrics.operations++;
performanceMetrics.totalTime += duration;
performanceMetrics.maxTime = Math.max(performanceMetrics.maxTime, duration);
performanceMetrics.minTime = Math.min(performanceMetrics.minTime, duration);
return result;
}
function getPerformanceStats() {
return {
operations: performanceMetrics.operations,
averageTime: performanceMetrics.totalTime / performanceMetrics.operations,
maxTime: performanceMetrics.maxTime,
minTime: performanceMetrics.minTime,
totalTime: performanceMetrics.totalTime
};
}
Memory Leaks Detection
function createLeak() {
const element = document.getElementById('myElement');
element.addEventListener('click', () => {
console.log('Clicked');
});
const handler = () => console.log('Clicked');
element.addEventListener('click', handler);
element._clickHandler = handler;
}
function cleanup(element) {
if (element._clickHandler) {
element.removeEventListener('click', element._clickHandler);
delete element._clickHandler;
}
}
const cache = new WeakMap();
function expensiveOperation(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = computeExpensiveResult(obj);
cache.set(obj, result);
return result;
}
const processedObjects = new WeakSet();
function processObject(obj) {
if (processedObjects.has(obj)) {
return;
}
processedObjects.add(obj);
}
Garbage Collection
if (global.gc) {
global.gc();
}
setInterval(() => {
const memUsage = process.memoryUsage();
console.log('Heap used:', Math.round(memUsage.heapUsed / 1024 / 1024), 'MB');
}, 5000);
let memorySnapshots = [];
function takeMemorySnapshot() {
if ('memory' in performance) {
memorySnapshots.push({
timestamp: Date.now(),
used: performance.memory.usedJSHeapSize,
total: performance.memory.totalJSHeapSize
});
if (memorySnapshots.length > 10) {
memorySnapshots.shift();
}
if (memorySnapshots.length >= 2) {
const growth = memorySnapshots[memorySnapshots.length - 1].used -
memorySnapshots[0].used;
if (growth > 10 * 1024 * 1024) {
console.warn('Potential memory leak detected');
}
}
}
}
Memory Optimization
class ObjectPool {
constructor(createFn, resetFn) {
this.pool = [];
this.createFn = createFn;
this.resetFn = resetFn;
}
get() {
return this.pool.pop() || this.createFn();
}
release(obj) {
this.resetFn(obj);
this.pool.push(obj);
}
}
const vectorPool = new ObjectPool(
() => ({ x: 0, y: 0 }),
(vector) => { vector.x = 0; vector.y = 0; }
);
function optimizedCalculation(x, y) {
return { x: x * 2, y: y * 2 };
result.x = x * 2;
result.y = y * 2;
return result;
}
Loop Optimization
const array = Array.from({ length: 10000 }, (_, i) => i);
for (let i = 0; i < array.length; i++) {
}
const len = array.length;
for (let i = 0; i < len; i++) {
}
for (const item of array) {
}
array.forEach(item => {
});
const doubled = array.map(item => item * 2);
for (const item of array) {
if (item > 100) break;
}
Function Optimization
function processItems(items) {
return items.map(item => {
return item * 2;
});
}
const double = item => item * 2;
function processItems(items) {
return items.map(double);
}
const memo = new Map();
function expensiveCalculation(n) {
if (memo.has(n)) {
return memo.get(n);
}
const result = ;
memo.set(n, result);
return result;
}
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);
}
};
}
const debouncedSearch = debounce(searchFunction, 300);
const throttledScroll = throttle(handleScroll, 100);
DOM Optimization
for (let i = 0; i < 100; i++) {
document.getElementById('element').style.color = 'red';
}
const element = document.getElementById('element');
for (let i = 0; i < 100; i++) {
element.style.color = 'red';
}
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
const updates = [];
function batchUpdate() {
requestAnimationFrame(() => {
updates.forEach(update => update());
updates.length = 0;
});
}
function scheduleUpdate(update) {
updates.push(update);
if (updates.length === 1) {
batchUpdate();
}
}
function createVirtualList(items, itemHeight, containerHeight) {
const visibleCount = Math.ceil(containerHeight / itemHeight);
const scrollTop = container.scrollTop;
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleCount, items.length);
return items.slice(startIndex, endIndex);
}
Algorithm Optimization
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}
const uniqueItems = new Set([1, 2, 3, 4, 5]);
console.log(uniqueItems.has(3));
const userCache = new Map();
userCache.set('user1', { name: 'John', age: 30 });
console.log(userCache.get('user1'));
let result = '';
for (let i = 0; i < 1000; i++) {
result += 'item' + i;
}
const parts = [];
for (let i = 0; i < 1000; i++) {
parts.push('item' + i);
}
const result = parts.join('');
Chrome DevTools
console.profile('My Operation');
console.profileEnd('My Operation');
console.profile('Memory Profile');
console.profileEnd('Memory Profile');
console.timeStamp('User clicked button');
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Performance entry:', entry);
}
});
observer.observe({ entryTypes: ['measure', 'navigation'] });
Node.js Profiling
const profiler = require('v8-profiler-next');
profiler.startProfiling('My Profile');
const profile = profiler.stopProfiling();
profile.export().pipe(require('fs').createWriteStream('profile.cpuprofile'));
const snapshot = profiler.takeSnapshot();
snapshot.export().pipe(require('fs').createWriteStream('heap.heapsnapshot'));
const inspector = require('inspector');
const session = new inspector.Session();
session.connect();
session.post('Profiler.enable');
session.post('Profiler.start');
session.post('Profiler.stop', (err, result) => {
console.log('Profile:', result.profile);
});
Performance Monitoring in Production
class PerformanceMonitor {
constructor() {
this.metrics = [];
}
measure(name, fn) {
const start = performance.now();
const result = fn();
const duration = performance.now() - start;
this.metrics.push({
name,
duration,
timestamp: Date.now()
});
if (duration > 100) {
this.reportSlowOperation(name, duration);
}
return result;
}
reportSlowOperation(name, duration) {
fetch('/api/metrics', {
method: 'POST',
body: JSON.stringify({ name, duration, timestamp: Date.now() })
});
}
}
const monitor = new PerformanceMonitor();
monitor.measure('expensiveOperation', () => {
});
Lazy Loading
const loadModule = async (moduleName) => {
const module = await import(`./modules/${moduleName}.js`);
return module.default;
};
function lazyLoadImages() {
const images = document.querySelectorAll('img[data-src]');
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
Caching Strategies
const cache = new Map();
function cachedFunction(key, fn) {
if (cache.has(key)) {
return cache.get(key);
}
const result = fn();
cache.set(key, result);
return result;
}
class LRUCache {
constructor(capacity) {
this.capacity = capacity;
this.cache = new Map();
}
get(key) {
if (this.cache.has(key)) {
const value = this.cache.get(key);
this.cache.delete(key);
this.cache.set(key, value);
return value;
}
return null;
}
put(key, value) {
if (this.cache.has(key)) {
this.cache.delete(key);
} else if (this.cache.size >= this.capacity) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
this.cache.set(key, value);
}
}
Web Workers
const worker = new Worker('worker.js');
worker.postMessage({ data: largeArray });
worker.onmessage = (event) => {
console.log('Result from worker:', event.data);
};
self.onmessage = (event) => {
const { data } = event.data;
const result = expensiveCalculation(data);
self.postMessage(result);
};