Prerequisites
- Basic understanding of JavaScript ๐
- TypeScript installation โก
- VS Code or preferred IDE ๐ป
What you'll learn
- Understand the concept fundamentals ๐ฏ
- Apply the concept in real projects ๐๏ธ
- Debug common issues ๐
- Write type-safe code โจ
๐ฏ Introduction
Welcome to this exciting tutorial on Runtime Performance: Execution Speed! ๐ In this guide, weโll explore how to make your TypeScript applications blazingly fast and optimize execution speed like a pro.
Youโll discover how understanding runtime performance can transform your TypeScript development experience. Whether youโre building web applications ๐, server-side code ๐ฅ๏ธ, or high-performance libraries ๐, mastering execution speed is essential for creating responsive, efficient applications that users love!
By the end of this tutorial, youโll feel confident optimizing TypeScript code for maximum performance! Letโs dive in! ๐โโ๏ธ
๐ Understanding Runtime Performance
๐ค What is Runtime Performance?
Runtime performance is like a race carโs engine ๐๏ธ. Think of it as the actual speed your code runs at when itโs executing, not just how fast it compiles. Itโs the difference between a sports car zooming past and a bicycle pedaling uphill!
In TypeScript terms, runtime performance focuses on how efficiently your JavaScript code (compiled from TypeScript) executes in the browser or Node.js environment. This means you can:
- โจ Make applications respond instantly to user actions
- ๐ Process large amounts of data without freezing
- ๐ก๏ธ Deliver smooth, lag-free user experiences
๐ก Why Focus on Execution Speed?
Hereโs why developers obsess over runtime performance:
- User Experience ๐ฏ: Fast apps = happy users
- Resource Efficiency ๐ป: Less CPU and memory usage
- Scalability ๐: Handle more users with same resources
- Cost Savings ๐ง: Reduced server costs and battery drain
Real-world example: Imagine building an e-commerce site ๐. With optimized execution speed, product searches return instantly, cart updates feel seamless, and checkout processes fly by!
๐ง Basic Syntax and Usage
๐ Measuring Performance
Letโs start with measuring execution speed:
// ๐ Hello, performance monitoring!
const startTime = performance.now();
// ๐จ Your code to measure
const numbers = Array.from({ length: 1000000 }, (_, i) => i);
const sum = numbers.reduce((acc, num) => acc + num, 0);
// โฑ๏ธ Calculate execution time
const endTime = performance.now();
console.log(`Execution time: ${endTime - startTime}ms ๐`);
// ๐ฏ Performance interface for precise measurements
interface PerformanceMetrics {
operation: string; // ๐ท๏ธ What we're measuring
duration: number; // โฑ๏ธ Time in milliseconds
timestamp: Date; // ๐
When it happened
}
๐ก Explanation: The performance.now()
API gives us high-resolution timestamps perfect for measuring code execution speed!
๐ฏ Common Performance Patterns
Here are patterns for faster code:
// ๐๏ธ Pattern 1: Efficient array operations
// โ Slow way - multiple iterations
const slowDoubleAndFilter = (arr: number[]): number[] => {
return arr.map(n => n * 2).filter(n => n > 10);
};
// โ
Fast way - single iteration
const fastDoubleAndFilter = (arr: number[]): number[] => {
const result: number[] = [];
for (const num of arr) {
const doubled = num * 2;
if (doubled > 10) {
result.push(doubled);
}
}
return result;
};
// ๐จ Pattern 2: Object lookup vs Array search
// โ Slow - O(n) search
const findUserSlow = (users: User[], id: string): User | undefined => {
return users.find(user => user.id === id);
};
// โ
Fast - O(1) lookup
const userMap = new Map<string, User>();
users.forEach(user => userMap.set(user.id, user));
const findUserFast = (id: string): User | undefined => {
return userMap.get(id);
};
๐ก Practical Examples
๐ Example 1: Optimized Shopping Cart
Letโs build a performance-focused shopping cart:
// ๐๏ธ Define our product type with performance in mind
interface Product {
id: string;
name: string;
price: number;
category: string;
emoji: string; // Every product needs an emoji!
}
// ๐ High-performance shopping cart
class PerformantCart {
// ๐ฏ Use Map for O(1) lookups
private items = new Map<string, { product: Product; quantity: number }>();
private totalCache: number | null = null;
// โ Add item efficiently
addItem(product: Product, quantity: number = 1): void {
const existing = this.items.get(product.id);
if (existing) {
existing.quantity += quantity;
} else {
this.items.set(product.id, { product, quantity });
}
// ๐ Invalidate cache
this.totalCache = null;
console.log(`Added ${quantity}x ${product.emoji} ${product.name} to cart!`);
}
// ๐ฐ Calculate total with caching
getTotal(): number {
// โจ Return cached value if available
if (this.totalCache !== null) {
return this.totalCache;
}
// ๐ฏ Calculate once and cache
let total = 0;
for (const [_, item] of this.items) {
total += item.product.price * item.quantity;
}
this.totalCache = total;
return total;
}
// ๐ Batch operations for better performance
addMultipleItems(items: Array<{ product: Product; quantity: number }>): void {
console.log("๐ฏ Batch adding items...");
const startTime = performance.now();
// ๐โโ๏ธ Process all at once
for (const item of items) {
const existing = this.items.get(item.product.id);
if (existing) {
existing.quantity += item.quantity;
} else {
this.items.set(item.product.id, item);
}
}
this.totalCache = null;
const endTime = performance.now();
console.log(`โจ Added ${items.length} items in ${endTime - startTime}ms!`);
}
}
// ๐ฎ Let's test performance!
const cart = new PerformantCart();
const products: Product[] = [
{ id: "1", name: "Gaming Mouse", price: 59.99, category: "electronics", emoji: "๐ฑ๏ธ" },
{ id: "2", name: "Mechanical Keyboard", price: 129.99, category: "electronics", emoji: "โจ๏ธ" },
{ id: "3", name: "Coffee Beans", price: 14.99, category: "food", emoji: "โ" }
];
// ๐ Batch add for best performance
cart.addMultipleItems(products.map(p => ({ product: p, quantity: 1 })));
๐ฏ Try it yourself: Add a method to remove items efficiently and update the cache strategy!
๐ฎ Example 2: High-Performance Game Engine
Letโs optimize a game loop:
// ๐ Optimized game entity system
interface GameEntity {
id: string;
x: number;
y: number;
velocityX: number;
velocityY: number;
sprite: string;
active: boolean;
}
class PerformantGameEngine {
// ๐ฏ Use typed arrays for maximum performance
private entities: GameEntity[] = [];
private entityPool: GameEntity[] = []; // Object pooling!
private lastFrameTime = 0;
// ๐ฎ Initialize with object pool
constructor(poolSize: number = 1000) {
// ๐โโ๏ธ Pre-allocate objects to avoid GC
for (let i = 0; i < poolSize; i++) {
this.entityPool.push({
id: `entity_${i}`,
x: 0, y: 0,
velocityX: 0, velocityY: 0,
sprite: "๐ฏ",
active: false
});
}
console.log(`๐ Game engine initialized with ${poolSize} pooled entities!`);
}
// โจ Spawn entity from pool (no allocation!)
spawnEntity(x: number, y: number, velocityX: number, velocityY: number): GameEntity | null {
const entity = this.entityPool.find(e => !e.active);
if (!entity) {
console.warn("โ ๏ธ Entity pool exhausted!");
return null;
}
// ๐ฏ Reuse existing object
entity.x = x;
entity.y = y;
entity.velocityX = velocityX;
entity.velocityY = velocityY;
entity.active = true;
this.entities.push(entity);
return entity;
}
// ๐ Optimized update loop
update(deltaTime: number): void {
const dt = deltaTime / 1000; // Convert to seconds
// ๐โโ๏ธ Cache array length
const len = this.entities.length;
// โก Use for loop (faster than forEach)
for (let i = len - 1; i >= 0; i--) {
const entity = this.entities[i];
if (!entity.active) {
// ๐ Return to pool
this.entities.splice(i, 1);
continue;
}
// ๐ฏ Direct property access (no method calls)
entity.x += entity.velocityX * dt;
entity.y += entity.velocityY * dt;
// ๐ Simple bounds check
if (entity.x < 0 || entity.x > 800 || entity.y < 0 || entity.y > 600) {
entity.active = false;
}
}
}
// ๐ Performance stats
getStats(): void {
console.log("๐ Engine Stats:");
console.log(` ๐ฎ Active entities: ${this.entities.length}`);
console.log(` ๐โโ๏ธ Pool available: ${this.entityPool.filter(e => !e.active).length}`);
console.log(` โก Memory efficient: Yes!`);
}
}
๐ Advanced Concepts
๐งโโ๏ธ Web Workers for Parallel Processing
When you need ultimate performance, offload work to Web Workers:
// ๐ฏ Heavy computation in a worker
interface ComputeTask {
id: string;
data: number[];
operation: "sum" | "average" | "max";
}
interface ComputeResult {
id: string;
result: number;
duration: number;
}
// ๐ช Worker manager for parallel processing
class ParallelComputer {
private workers: Worker[] = [];
private taskQueue: ComputeTask[] = [];
private results = new Map<string, ComputeResult>();
constructor(workerCount: number = navigator.hardwareConcurrency || 4) {
// ๐ Spawn worker threads
for (let i = 0; i < workerCount; i++) {
const worker = new Worker("compute-worker.js");
worker.onmessage = this.handleResult.bind(this);
this.workers.push(worker);
}
console.log(`โจ Spawned ${workerCount} worker threads!`);
}
// ๐ฏ Process data in parallel
async compute(task: ComputeTask): Promise<ComputeResult> {
return new Promise((resolve) => {
const startTime = performance.now();
// ๐โโ๏ธ Find available worker
const worker = this.workers[Math.floor(Math.random() * this.workers.length)];
// ๐จ Send task to worker
worker.postMessage({ ...task, startTime });
// ๐ฏ Store resolver
this.results.set(task.id, {
id: task.id,
result: 0,
duration: 0
} as any);
// Wait for result...
});
}
private handleResult(event: MessageEvent<ComputeResult>): void {
const { id, result, duration } = event.data;
console.log(`โจ Task ${id} completed in ${duration}ms!`);
this.results.set(id, { id, result, duration });
}
}
๐๏ธ Memory-Efficient Data Structures
For maximum speed, use the right data structures:
// ๐ Custom high-performance collection
class FastSet<T> {
private items: T[] = [];
private indices = new Map<T, number>();
// โก O(1) add operation
add(item: T): void {
if (!this.indices.has(item)) {
const index = this.items.length;
this.items.push(item);
this.indices.set(item, index);
}
}
// ๐ฏ O(1) contains check
has(item: T): boolean {
return this.indices.has(item);
}
// ๐ O(1) delete operation
delete(item: T): boolean {
const index = this.indices.get(item);
if (index === undefined) return false;
// ๐จ Swap with last element
const lastItem = this.items[this.items.length - 1];
this.items[index] = lastItem;
this.items.pop();
// ๐ Update indices
this.indices.set(lastItem, index);
this.indices.delete(item);
return true;
}
}
โ ๏ธ Common Pitfalls and Solutions
๐ฑ Pitfall 1: Premature Optimization
// โ Wrong way - optimizing before measuring!
const overEngineered = (arr: number[]): number => {
// Complex bit manipulation for simple addition ๐ฐ
return arr.reduce((a, b) => (a ^ b) ^ ((a & b) << 1), 0);
};
// โ
Correct way - measure first, optimize what matters!
const measureFirst = (arr: number[]): number => {
const start = performance.now();
const result = arr.reduce((a, b) => a + b, 0);
const duration = performance.now() - start;
// ๐ Only optimize if it's actually slow
if (duration > 10) {
console.log("โ ๏ธ This operation is slow, consider optimization!");
}
return result;
};
๐คฏ Pitfall 2: Memory Leaks
// โ Dangerous - keeping references forever!
class LeakyEventManager {
private handlers: Function[] = [];
subscribe(handler: Function): void {
this.handlers.push(handler); // ๐ฅ Never removed!
}
}
// โ
Safe - proper cleanup!
class SafeEventManager {
private handlers = new Map<string, Function>();
subscribe(id: string, handler: Function): () => void {
this.handlers.set(id, handler);
// ๐ฏ Return unsubscribe function
return () => {
this.handlers.delete(id);
console.log("โ
Handler cleaned up!");
};
}
}
๐ ๏ธ Best Practices
- ๐ฏ Measure First: Profile before optimizing - donโt guess!
- ๐ Use Appropriate Data Structures: Map for lookups, Set for uniqueness
- ๐ก๏ธ Avoid Premature Optimization: Clean code first, fast code second
- ๐จ Cache Expensive Operations: Donโt recalculate unchanged data
- โจ Use Web Workers: Offload heavy computations
- ๐ Batch Operations: Process multiple items together
- ๐ก Object Pooling: Reuse objects to reduce GC pressure
๐งช Hands-On Exercise
๐ฏ Challenge: Build a High-Performance Search Engine
Create a blazingly fast search system:
๐ Requirements:
- โ Search through 100,000+ items instantly
- ๐ท๏ธ Support fuzzy matching and filters
- ๐ค Handle concurrent searches
- ๐ Cache recent searches
- ๐จ Show search performance metrics!
๐ Bonus Points:
- Implement search-as-you-type with debouncing
- Add search result ranking algorithm
- Create performance benchmarks
๐ก Solution
๐ Click to see solution
// ๐ฏ Our high-performance search engine!
interface SearchItem {
id: string;
title: string;
description: string;
category: string;
tags: string[];
score: number;
}
class LightningSearchEngine {
private items: SearchItem[] = [];
private searchIndex = new Map<string, Set<string>>();
private cache = new Map<string, SearchItem[]>();
private cacheSize = 100;
// ๐ Build search index for O(1) lookups
constructor(items: SearchItem[]) {
console.log(`๐๏ธ Building search index for ${items.length} items...`);
const startTime = performance.now();
this.items = items;
// ๐ฏ Index all searchable terms
for (const item of items) {
this.indexItem(item);
}
const duration = performance.now() - startTime;
console.log(`โจ Index built in ${duration}ms!`);
}
private indexItem(item: SearchItem): void {
// ๐ Index title words
const words = this.tokenize(item.title + " " + item.description);
for (const word of words) {
if (!this.searchIndex.has(word)) {
this.searchIndex.set(word, new Set());
}
this.searchIndex.get(word)!.add(item.id);
}
// ๐ท๏ธ Index tags
for (const tag of item.tags) {
const normalized = tag.toLowerCase();
if (!this.searchIndex.has(normalized)) {
this.searchIndex.set(normalized, new Set());
}
this.searchIndex.get(normalized)!.add(item.id);
}
}
private tokenize(text: string): string[] {
return text.toLowerCase()
.replace(/[^\w\s]/g, '')
.split(/\s+/)
.filter(word => word.length > 2);
}
// โก Lightning-fast search
search(query: string, limit: number = 20): SearchItem[] {
const startTime = performance.now();
// ๐ฏ Check cache first
const cacheKey = `${query}:${limit}`;
if (this.cache.has(cacheKey)) {
console.log("โก Cache hit!");
return this.cache.get(cacheKey)!;
}
// ๐ Tokenize query
const queryWords = this.tokenize(query);
const matches = new Map<string, number>();
// ๐โโ๏ธ Find matching items
for (const word of queryWords) {
const itemIds = this.searchIndex.get(word);
if (itemIds) {
for (const id of itemIds) {
matches.set(id, (matches.get(id) || 0) + 1);
}
}
}
// ๐ฏ Score and sort results
const results = Array.from(matches.entries())
.map(([id, score]) => {
const item = this.items.find(i => i.id === id)!;
return { ...item, score };
})
.sort((a, b) => b.score - a.score)
.slice(0, limit);
// ๐พ Update cache
this.updateCache(cacheKey, results);
const duration = performance.now() - startTime;
console.log(`๐ Search completed in ${duration}ms!`);
return results;
}
private updateCache(key: string, results: SearchItem[]): void {
this.cache.set(key, results);
// ๐ LRU cache eviction
if (this.cache.size > this.cacheSize) {
const firstKey = this.cache.keys().next().value;
this.cache.delete(firstKey);
}
}
// ๐ Performance stats
getStats(): void {
console.log("๐ Search Engine Stats:");
console.log(` ๐ Indexed items: ${this.items.length}`);
console.log(` ๐ Index size: ${this.searchIndex.size} terms`);
console.log(` ๐พ Cache entries: ${this.cache.size}`);
console.log(` โก Ready for lightning-fast searches!`);
}
}
// ๐ฎ Test it out!
const testItems: SearchItem[] = Array.from({ length: 100000 }, (_, i) => ({
id: `item_${i}`,
title: `Product ${i}`,
description: `Amazing product number ${i} with great features`,
category: ["electronics", "clothing", "food"][i % 3],
tags: [`tag${i % 10}`, `special${i % 20}`],
score: 0
}));
const searchEngine = new LightningSearchEngine(testItems);
searchEngine.search("amazing product");
searchEngine.getStats();
๐ Key Takeaways
Youโve learned so much about runtime performance! Hereโs what you can now do:
- โ Measure performance accurately with performance.now() ๐ช
- โ Optimize algorithms for maximum speed ๐ก๏ธ
- โ Choose efficient data structures for your use case ๐ฏ
- โ Implement caching strategies like a pro ๐
- โ Build blazingly fast TypeScript applications! ๐
Remember: Performance optimization is a journey, not a destination! Always measure, never assume. ๐ค
๐ค Next Steps
Congratulations! ๐ Youโve mastered runtime performance and execution speed!
Hereโs what to do next:
- ๐ป Practice with the search engine exercise above
- ๐๏ธ Profile your existing projects for performance bottlenecks
- ๐ Move on to our next tutorial: Memory Management and Garbage Collection
- ๐ Share your performance wins with the community!
Remember: Every millisecond counts when building great user experiences. Keep optimizing, keep measuring, and most importantly, have fun making things fast! ๐
Happy coding! ๐๐โจ