By the end of this lesson, you will be able to:
ℹ️ Info Definition: Performance optimization is the systematic process of improving app speed, responsiveness, and efficiency. Great performance isn't just about fast loading times-it's about creating delightful, friction-free experiences that keep users engaged and coming back.
Performance directly impacts user satisfaction and business metrics:
Performance Factor | User Experience Impact | Business Impact | Optimization ROI |
---|---|---|---|
App Launch Time | First impression | Install-to-use conversion | 300-500% |
UI Responsiveness | Touch interaction quality | Session duration | 200-400% |
Memory Usage | App stability | Crash rates | 150-300% |
Network Efficiency | Data usage | User satisfaction | 100-250% |
Battery Optimization | Device longevity | App store ratings | 50-150% |
💡 Performance Insight: Apps that maintain consistent 60fps performance see 2.5x higher user engagement compared to those with frequent frame drops!
// services/PerformanceMonitor.ts
import { Platform } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
interface PerformanceMetric {
name: string;
value: number;
timestamp: Date;
metadata?: Record<string, any>;
}
interface FrameDropInfo {
droppedFrames: number;
totalFrames: number;
duration: number;
screen: string;
timestamp: Date;
}
interface MemoryUsage {
used: number;
total: number;
available: number;
timestamp: Date;
}
interface BundleSizeInfo {
totalSize: number;
codeSize: number;
assetsSize: number;
unusedCode: number;
}
class PerformanceMonitor {
private static instance: PerformanceMonitor;
private metrics: PerformanceMetric[] = [];
private frameDrops: FrameDropInfo[] = [];
private memoryUsage: MemoryUsage[] = [];
private isMonitoring = false;
private frameDropCallback: any = null;
static getInstance(): PerformanceMonitor {
if (!PerformanceMonitor.instance) {
PerformanceMonitor.instance = new PerformanceMonitor();
}
return PerformanceMonitor.instance;
}
async startMonitoring(): Promise<void> {
if (this.isMonitoring) return;
this.isMonitoring = true;
console.log('Performance monitoring started');
// Monitor JavaScript thread frame drops
this.startFrameDropMonitoring();
// Monitor memory usage
this.startMemoryMonitoring();
// Monitor app lifecycle events
this.startLifecycleMonitoring();
// Store monitoring session start
await this.trackMetric('monitoring_session_start', 1);
}
stopMonitoring(): void {
this.isMonitoring = false;
if (this.frameDropCallback) {
this.frameDropCallback = null;
}
console.log('Performance monitoring stopped');
}
private startFrameDropMonitoring(): void {
// Note: In a real implementation, you'd use libraries like
// react-native-performance-monitor or flipper-plugin-performance
let frameCount = 0;
let droppedFrames = 0;
let startTime = performance.now();
const checkFrames = () => {
if (!this.isMonitoring) return;
const currentTime = performance.now();
const elapsed = currentTime - startTime;
// Simulate frame drop detection (in real app, use actual frame metrics)
const expectedFrames = Math.floor(elapsed / 16.67); // 60 FPS = 16.67ms per frame
frameCount++;
// Detect frame drops (simplified simulation)
if (elapsed > frameCount * 20) { // More than 20ms per frame indicates drops
droppedFrames++;
this.frameDrops.push({
droppedFrames,
totalFrames: frameCount,
duration: elapsed,
screen: 'current_screen', // Would get actual screen name
timestamp: new Date(),
});
// Track significant frame drops
if (droppedFrames > 5) {
this.trackMetric('frame_drops_detected', droppedFrames, {
screen: 'current_screen',
duration: elapsed,
});
}
}
// Reset counters every 5 seconds
if (elapsed > 5000) {
startTime = currentTime;
frameCount = 0;
droppedFrames = 0;
}
// Continue monitoring
this.frameDropCallback = requestAnimationFrame(checkFrames);
};
this.frameDropCallback = requestAnimationFrame(checkFrames);
}
private startMemoryMonitoring(): void {
const checkMemory = () => {
if (!this.isMonitoring) return;
// React Native memory monitoring (simplified)
if (Platform.OS === 'ios' && (performance as any).memory) {
const memInfo = (performance as any).memory;
const memoryData: MemoryUsage = {
used: memInfo.usedJSHeapSize,
total: memInfo.totalJSHeapSize,
available: memInfo.totalJSHeapSize - memInfo.usedJSHeapSize,
timestamp: new Date(),
};
this.memoryUsage.push(memoryData);
// Alert on high memory usage
const usagePercentage = (memoryData.used / memoryData.total) * 100;
if (usagePercentage > 80) {
this.trackMetric('high_memory_usage', usagePercentage, {
used_mb: Math.round(memoryData.used / 1024 / 1024),
total_mb: Math.round(memoryData.total / 1024 / 1024),
});
}
// Keep only last 100 memory readings
if (this.memoryUsage.length > 100) {
this.memoryUsage = this.memoryUsage.slice(-100);
}
}
setTimeout(checkMemory, 10000); // Check every 10 seconds
};
checkMemory();
}
private startLifecycleMonitoring(): void {
// Monitor app state changes and their performance impact
const handleAppStateChange = (nextAppState: string) => {
this.trackMetric('app_state_change', 1, {
new_state: nextAppState,
timestamp: new Date().toISOString(),
});
};
// In a real app, you'd import AppState from 'react-native'
// AppState.addEventListener('change', handleAppStateChange);
}
async trackMetric(name: string, value: number, metadata?: Record<string, any>): Promise<void> {
const metric: PerformanceMetric = {
name,
value,
timestamp: new Date(),
metadata,
};
this.metrics.push(metric);
// Store critical metrics immediately
if (this.isCriticalMetric(name)) {
await this.persistMetrics();
}
// Keep only last 1000 metrics in memory
if (this.metrics.length > 1000) {
this.metrics = this.metrics.slice(-1000);
}
console.log(`Performance metric tracked: ${name} = ${value}`);
}
private isCriticalMetric(name: string): boolean {
const criticalMetrics = [
'app_crash',
'high_memory_usage',
'frame_drops_detected',
'slow_navigation',
'api_timeout',
];
return criticalMetrics.includes(name);
}
async measureRenderTime<T>(componentName: string, renderFunction: () => T): Promise<T> {
const startTime = performance.now();
try {
const result = renderFunction();
const endTime = performance.now();
const renderTime = endTime - startTime;
await this.trackMetric('component_render_time', renderTime, {
component: componentName,
});
// Warn about slow renders
if (renderTime > 16.67) {
console.warn(`Slow render detected: ${componentName} took ${renderTime.toFixed(2)}ms`);
}
return result;
} catch (error) {
const endTime = performance.now();
const renderTime = endTime - startTime;
await this.trackMetric('component_render_error', renderTime, {
component: componentName,
error: error instanceof Error ? error.message : 'Unknown error',
});
throw error;
}
}
async measureAsyncOperation<T>(
operationName: string,
operation: () => Promise<T>
): Promise<T> {
const startTime = performance.now();
try {
const result = await operation();
const endTime = performance.now();
const duration = endTime - startTime;
await this.trackMetric('async_operation_duration', duration, {
operation: operationName,
success: true,
});
return result;
} catch (error) {
const endTime = performance.now();
const duration = endTime - startTime;
await this.trackMetric('async_operation_duration', duration, {
operation: operationName,
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
});
throw error;
}
}
async getPerformanceReport(): Promise<{
summary: {
averageRenderTime: number;
totalFrameDrops: number;
averageMemoryUsage: number;
criticalIssues: number;
};
frameDrops: FrameDropInfo[];
memoryTrend: MemoryUsage[];
topSlowComponents: Array<{ component: string; averageTime: number; count: number }>;
recommendations: string[];
}> {
const renderTimeMetrics = this.metrics.filter(m => m.name === 'component_render_time');
const averageRenderTime = renderTimeMetrics.length > 0
? renderTimeMetrics.reduce((sum, m) => sum + m.value, 0) / renderTimeMetrics.length
: 0;
const totalFrameDrops = this.frameDrops.reduce((sum, fd) => sum + fd.droppedFrames, 0);
const averageMemoryUsage = this.memoryUsage.length > 0
? this.memoryUsage.reduce((sum, m) => sum + m.used, 0) / this.memoryUsage.length
: 0;
const criticalIssues = this.metrics.filter(m => this.isCriticalMetric(m.name)).length;
// Analyze slow components
const componentTimes: Record<string, { total: number; count: number }> = {};
renderTimeMetrics.forEach(metric => {
const component = metric.metadata?.component || 'unknown';
if (!componentTimes[component]) {
componentTimes[component] = { total: 0, count: 0 };
}
componentTimes[component].total += metric.value;
componentTimes[component].count++;
});
const topSlowComponents = Object.entries(componentTimes)
.map(([component, data]) => ({
component,
averageTime: data.total / data.count,
count: data.count,
}))
.sort((a, b) => b.averageTime - a.averageTime)
.slice(0, 5);
// Generate recommendations
const recommendations = this.generateRecommendations({
averageRenderTime,
totalFrameDrops,
averageMemoryUsage,
criticalIssues,
});
return {
summary: {
averageRenderTime,
totalFrameDrops,
averageMemoryUsage,
criticalIssues,
},
frameDrops: this.frameDrops.slice(-10), // Last 10 frame drop events
memoryTrend: this.memoryUsage.slice(-20), // Last 20 memory readings
topSlowComponents,
recommendations,
};
}
private generateRecommendations(summary: any): string[] {
const recommendations: string[] = [];
if (summary.averageRenderTime > 16.67) {
recommendations.push('Optimize component renders - consider using React.memo and useMemo');
}
if (summary.totalFrameDrops > 10) {
recommendations.push('Reduce frame drops by optimizing animations and heavy computations');
}
if (summary.averageMemoryUsage > 100 * 1024 * 1024) { // 100MB
recommendations.push('Optimize memory usage - check for memory leaks and large object retention');
}
if (summary.criticalIssues > 5) {
recommendations.push('Address critical performance issues immediately');
}
return recommendations;
}
private async persistMetrics(): Promise<void> {
try {
const metricsToStore = this.metrics.slice(-100); // Store last 100 metrics
await AsyncStorage.setItem('performance_metrics', JSON.stringify(metricsToStore));
} catch (error) {
console.error('Error persisting performance metrics:', error);
}
}
async getBundleAnalysis(): Promise<BundleSizeInfo> {
// In a real app, this would analyze the actual bundle
// For now, return mock data
return {
totalSize: 15.2 * 1024 * 1024, // 15.2 MB
codeSize: 8.5 * 1024 * 1024, // 8.5 MB
assetsSize: 6.7 * 1024 * 1024, // 6.7 MB
unusedCode: 1.2 * 1024 * 1024, // 1.2 MB
};
}
}
export default PerformanceMonitor;
// utils/MemoryOptimizer.ts
import { Dimensions, PixelRatio } from 'react-native';
interface ImageOptimizationOptions {
maxWidth?: number;
maxHeight?: number;
quality?: number; // 0-1
format?: 'jpeg' | 'png' | 'webp';
progressive?: boolean;
}
interface CacheOptions {
maxSize?: number; // in MB
maxAge?: number; // in milliseconds
compressionLevel?: number; // 0-9
}
class MemoryOptimizer {
private static instance: MemoryOptimizer;
private imageCache = new Map<string, { data: any; timestamp: number; size: number }>();
private maxCacheSize: number; // in bytes
private cleanupInterval: NodeJS.Timeout | null = null;
constructor() {
this.maxCacheSize = 50 * 1024 * 1024; // 50MB default cache size
this.startCleanupScheduler();
}
static getInstance(): MemoryOptimizer {
if (!MemoryOptimizer.instance) {
MemoryOptimizer.instance = new MemoryOptimizer();
}
return MemoryOptimizer.instance;
}
// Image optimization for different screen densities
optimizeImageForDevice(originalUri: string, options: ImageOptimizationOptions = {}): {
uri: string;
width: number;
height: number;
estimatedSize: number;
} {
const screenData = Dimensions.get('window');
const pixelRatio = PixelRatio.get();
const maxWidth = options.maxWidth || screenData.width * pixelRatio;
const maxHeight = options.maxHeight || screenData.height * pixelRatio;
// Calculate optimized dimensions
const optimizedDimensions = this.calculateOptimalImageSize(
maxWidth,
maxHeight,
screenData.width,
screenData.height
);
// Generate optimized image URI (in a real app, this would call an image optimization service)
const optimizedUri = this.generateOptimizedImageUri(originalUri, {
...options,
width: optimizedDimensions.width,
height: optimizedDimensions.height,
});
const estimatedSize = this.estimateImageSize(
optimizedDimensions.width,
optimizedDimensions.height,
options.quality || 0.8
);
return {
uri: optimizedUri,
width: optimizedDimensions.width,
height: optimizedDimensions.height,
estimatedSize,
};
}
private calculateOptimalImageSize(
maxWidth: number,
maxHeight: number,
displayWidth: number,
displayHeight: number
): { width: number; height: number } {
// Calculate aspect ratio preservation
const aspectRatio = displayWidth / displayHeight;
let optimalWidth = Math.min(maxWidth, displayWidth * PixelRatio.get());
let optimalHeight = Math.min(maxHeight, displayHeight * PixelRatio.get());
// Maintain aspect ratio
if (optimalWidth / optimalHeight > aspectRatio) {
optimalWidth = optimalHeight * aspectRatio;
} else {
optimalHeight = optimalWidth / aspectRatio;
}
// Round to even numbers for better compression
return {
width: Math.round(optimalWidth / 2) * 2,
height: Math.round(optimalHeight / 2) * 2,
};
}
private generateOptimizedImageUri(originalUri: string, options: any): string {
// In a real app, this would generate URLs for image optimization services
// like Cloudinary, ImageKit, or your own optimization endpoint
const params = new URLSearchParams({
w: options.width?.toString() || '',
h: options.height?.toString() || '',
q: Math.round((options.quality || 0.8) * 100).toString(),
f: options.format || 'jpeg',
});
return `${originalUri}?${params.toString()}`;
}
private estimateImageSize(width: number, height: number, quality: number): number {
// Rough estimation of JPEG file size
const pixels = width * height;
const bytesPerPixel = quality * 3; // RGB channels with quality factor
const compressionRatio = 0.1 + (quality * 0.2); // JPEG compression
return Math.round(pixels * bytesPerPixel * compressionRatio);
}
// Smart caching with memory pressure handling
async cacheData<T>(key: string, data: T, options: CacheOptions = {}): Promise<void> {
const serializedData = JSON.stringify(data);
const size = new Blob([serializedData]).size;
const maxAge = options.maxAge || 30 * 60 * 1000; // 30 minutes default
// Check if cache would exceed memory limit
if (this.getCurrentCacheSize() + size > this.maxCacheSize) {
await this.evictLeastRecentlyUsed(size);
}
this.imageCache.set(key, {
data,
timestamp: Date.now(),
size,
});
}
getCachedData<T>(key: string): T | null {
const cached = this.imageCache.get(key);
if (!cached) return null;
// Check if expired
const maxAge = 30 * 60 * 1000; // 30 minutes
if (Date.now() - cached.timestamp > maxAge) {
this.imageCache.delete(key);
return null;
}
// Update access timestamp (LRU)
cached.timestamp = Date.now();
this.imageCache.set(key, cached);
return cached.data as T;
}
private getCurrentCacheSize(): number {
return Array.from(this.imageCache.values())
.reduce((total, item) => total + item.size, 0);
}
private async evictLeastRecentlyUsed(requiredSpace: number): Promise<void> {
const entries = Array.from(this.imageCache.entries())
.sort(([,a], [,b]) => a.timestamp - b.timestamp); // Sort by oldest first
let freedSpace = 0;
for (const [key, value] of entries) {
this.imageCache.delete(key);
freedSpace += value.size;
if (freedSpace >= requiredSpace) {
break;
}
}
console.log(`Evicted ${freedSpace} bytes from cache`);
}
// List optimization for large datasets
optimizeListData<T extends { id: string | number }>(
data: T[],
viewportSize: number,
itemHeight: number
): {
visibleItems: T[];
totalHeight: number;
shouldVirtualize: boolean;
} {
const shouldVirtualize = data.length > 100 || data.length * itemHeight > 10000;
if (!shouldVirtualize) {
return {
visibleItems: data,
totalHeight: data.length * itemHeight,
shouldVirtualize: false,
};
}
// Calculate visible range with buffer
const itemsPerScreen = Math.ceil(viewportSize / itemHeight);
const bufferSize = Math.min(50, itemsPerScreen * 2); // Buffer 2 screens worth
const visibleItems = data.slice(0, itemsPerScreen + bufferSize);
return {
visibleItems,
totalHeight: data.length * itemHeight,
shouldVirtualize: true,
};
}
// Component optimization helpers
shouldComponentUpdate<T>(prevProps: T, nextProps: T, shallowCompareKeys?: (keyof T)[]): boolean {
if (!shallowCompareKeys) {
return this.shallowEqual(prevProps, nextProps);
}
return shallowCompareKeys.some(key => prevProps[key] !== nextProps[key]);
}
private shallowEqual<T>(obj1: T, obj2: T): boolean {
if (obj1 === obj2) return true;
if (!obj1 || !obj2) return false;
const keys1 = Object.keys(obj1 as any);
const keys2 = Object.keys(obj2 as any);
if (keys1.length !== keys2.length) return false;
return keys1.every(key => (obj1 as any)[key] === (obj2 as any)[key]);
}
// Memory leak detection
detectPotentialLeaks(): {
cacheSize: number;
cacheItems: number;
recommendations: string[];
} {
const cacheSize = this.getCurrentCacheSize();
const cacheItems = this.imageCache.size;
const recommendations: string[] = [];
if (cacheSize > 100 * 1024 * 1024) { // 100MB
recommendations.push('Cache size is very large - consider reducing cache size or implementing more aggressive eviction');
}
if (cacheItems > 1000) {
recommendations.push('Large number of cached items - implement better cache key strategies');
}
// Check for old cached items
const oldItems = Array.from(this.imageCache.values())
.filter(item => Date.now() - item.timestamp > 60 * 60 * 1000); // 1 hour old
if (oldItems.length > 100) {
recommendations.push('Many old cached items found - increase cleanup frequency');
}
return {
cacheSize,
cacheItems,
recommendations,
};
}
private startCleanupScheduler(): void {
// Clean up expired cache entries every 5 minutes
this.cleanupInterval = setInterval(() => {
this.cleanupExpiredEntries();
}, 5 * 60 * 1000);
}
private cleanupExpiredEntries(): void {
const maxAge = 30 * 60 * 1000; // 30 minutes
const now = Date.now();
let cleanedItems = 0;
for (const [key, value] of this.imageCache.entries()) {
if (now - value.timestamp > maxAge) {
this.imageCache.delete(key);
cleanedItems++;
}
}
if (cleanedItems > 0) {
console.log(`Cleaned up ${cleanedItems} expired cache entries`);
}
}
cleanup(): void {
if (this.cleanupInterval) {
clearInterval(this.cleanupInterval);
this.cleanupInterval = null;
}
this.imageCache.clear();
}
}
export default MemoryOptimizer;
// services/PerformanceIntelligence.ts
import OpenAI from 'openai';
import PerformanceMonitor from './PerformanceMonitor';
import MemoryOptimizer from '../utils/MemoryOptimizer';
interface PerformanceAnalysis {
overallScore: number; // 0-100
categories: {
renderPerformance: number;
memoryEfficiency: number;
networkOptimization: number;
batteryUsage: number;
};
criticalIssues: Array<{
type: 'memory' | 'render' | 'network' | 'battery';
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
solution: string;
estimatedImpact: string;
}>;
optimizationPlan: Array<{
priority: number;
action: string;
expectedImprovement: string;
implementationEffort: 'low' | 'medium' | 'high';
}>;
}
interface CodeOptimizationSuggestion {
file: string;
line?: number;
issue: string;
suggestion: string;
impact: 'low' | 'medium' | 'high';
automated: boolean; // Can be fixed automatically
}
class PerformanceIntelligence {
private openai: OpenAI;
private performanceMonitor: PerformanceMonitor;
private memoryOptimizer: MemoryOptimizer;
constructor(apiKey: string) {
this.openai = new OpenAI({ apiKey });
this.performanceMonitor = PerformanceMonitor.getInstance();
this.memoryOptimizer = MemoryOptimizer.getInstance();
}
async analyzeAppPerformance(): Promise<PerformanceAnalysis> {
try {
// Gather performance data
const performanceReport = await this.performanceMonitor.getPerformanceReport();
const memoryLeaks = this.memoryOptimizer.detectPotentialLeaks();
const bundleInfo = await this.performanceMonitor.getBundleAnalysis();
// Use AI to analyze the data
const aiAnalysis = await this.generateAIAnalysis({
performanceReport,
memoryLeaks,
bundleInfo,
});
return aiAnalysis;
} catch (error) {
console.error('Performance analysis error:', error);
return this.getFallbackAnalysis();
}
}
private async generateAIAnalysis(data: any): Promise<PerformanceAnalysis> {
const prompt = `
Analyze React Native app performance data and provide optimization recommendations:
Performance Metrics:
- Average render time: ${data.performanceReport.summary.averageRenderTime.toFixed(2)}ms
- Frame drops: ${data.performanceReport.summary.totalFrameDrops}
- Memory usage: ${Math.round(data.performanceReport.summary.averageMemoryUsage / 1024 / 1024)}MB
- Critical issues: ${data.performanceReport.summary.criticalIssues}
Bundle Analysis:
- Total size: ${Math.round(data.bundleInfo.totalSize / 1024 / 1024)}MB
- Code size: ${Math.round(data.bundleInfo.codeSize / 1024 / 1024)}MB
- Unused code: ${Math.round(data.bundleInfo.unusedCode / 1024 / 1024)}MB
Memory Analysis:
- Cache size: ${Math.round(data.memoryLeaks.cacheSize / 1024 / 1024)}MB
- Cache items: ${data.memoryLeaks.cacheItems}
Slow Components: ${data.performanceReport.topSlowComponents.map((c: any) =>
`${c.component}: ${c.averageTime.toFixed(2)}ms`).join(', ')}
Provide:
1. Overall performance score (0-100)
2. Category scores for render, memory, network, battery
3. Critical issues with severity and solutions
4. Optimization plan with priorities
Return as JSON matching PerformanceAnalysis interface.
`;
const response = await this.openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
temperature: 0.3,
});
return JSON.parse(response.choices[0].message.content || '{}');
}
async optimizeComponentCode(componentCode: string, componentName: string): Promise<CodeOptimizationSuggestion[]> {
const prompt = `
Analyze this React Native component for performance optimizations:
Component: ${componentName}
Code:
\`\`\`typescript
${componentCode}
\`\`\`
Identify performance issues and provide specific optimization suggestions:
1. Unnecessary re-renders
2. Missing memoization opportunities
3. Inefficient list rendering
4. Heavy computations in render
5. Memory leaks
6. Incorrect dependency arrays
For each issue, provide:
- Specific line/area of concern
- Clear explanation of the problem
- Concrete solution with code example
- Impact assessment
- Whether it can be automatically fixed
Return as JSON array of CodeOptimizationSuggestion objects.
`;
try {
const response = await this.openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
temperature: 0.3,
});
return JSON.parse(response.choices[0].message.content || '[]');
} catch (error) {
console.error('Code optimization error:', error);
return [];
}
}
async generateOptimizedComponent(originalCode: string, optimizations: CodeOptimizationSuggestion[]): Promise<string> {
const prompt = `
Apply these optimizations to the React Native component:
Original Code:
\`\`\`typescript
${originalCode}
\`\`\`
Optimizations to apply:
${optimizations.map((opt, i) => `
${i + 1}. ${opt.issue}
Solution: ${opt.suggestion}
`).join('\n')}
Generate the optimized component code with:
1. All suggested optimizations applied
2. Proper TypeScript typing
3. Clear comments explaining optimizations
4. Maintained functionality
Return only the optimized code, no explanations.
`;
try {
const response = await this.openai.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
temperature: 0.2,
});
return response.choices[0].message.content || originalCode;
} catch (error) {
console.error('Component optimization error:', error);
return originalCode;
}
}
async predictPerformanceImpact(changes: string[]): Promise<{
renderImpact: number;
memoryImpact: number;
bundleSizeImpact: number;
batteryImpact: number;
overallScore: number;
}> {
const prompt = `
Predict the performance impact of these React Native app changes:
Changes:
${changes.map((change, i) => `${i + 1}. ${change}`).join('\n')}
For each impact category, predict the change as a percentage:
- Render Performance: Speed of UI updates and animations
- Memory Usage: RAM consumption and efficiency
- Bundle Size: App download and installation size
- Battery Usage: Device battery consumption
- Overall Performance: Combined user experience
Use positive percentages for improvements, negative for degradation.
Consider both immediate and long-term impacts.
Return as JSON with impact percentages.
`;
try {
const response = await this.openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [{ role: 'user', content: prompt }],
temperature: 0.3,
});
return JSON.parse(response.choices[0].message.content || '{}');
} catch (error) {
console.error('Performance prediction error:', error);
return {
renderImpact: 0,
memoryImpact: 0,
bundleSizeImpact: 0,
batteryImpact: 0,
overallScore: 0,
};
}
}
private getFallbackAnalysis(): PerformanceAnalysis {
return {
overallScore: 75,
categories: {
renderPerformance: 80,
memoryEfficiency: 70,
networkOptimization: 75,
batteryUsage: 80,
},
criticalIssues: [
{
type: 'memory',
severity: 'medium',
description: 'Memory usage is above recommended levels',
solution: 'Implement proper cleanup in useEffect hooks',
estimatedImpact: '15% reduction in memory usage',
},
],
optimizationPlan: [
{
priority: 1,
action: 'Optimize component re-renders with React.memo',
expectedImprovement: '20% faster UI updates',
implementationEffort: 'medium',
},
{
priority: 2,
action: 'Implement image lazy loading',
expectedImprovement: '30% faster screen loads',
implementationEffort: 'low',
},
],
};
}
async runAutomatedOptimizations(): Promise<{
applied: number;
failed: number;
results: Array<{
optimization: string;
success: boolean;
error?: string;
}>;
}> {
// This would implement automated code fixes
// For now, return mock results
return {
applied: 3,
failed: 1,
results: [
{
optimization: 'Add React.memo to SlowComponent',
success: true,
},
{
optimization: 'Optimize image loading in Gallery',
success: true,
},
{
optimization: 'Fix memory leak in EventListener',
success: true,
},
{
optimization: 'Complex refactoring required',
success: false,
error: 'Manual intervention needed',
},
],
};
}
}
export default PerformanceIntelligence;
// components/PerformanceMonitoringUI.tsx
import React, { useState, useEffect } from 'react';
import {
View,
Text,
ScrollView,
StyleSheet,
TouchableOpacity,
Alert,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { LineChart, BarChart } from 'react-native-chart-kit';
import { Dimensions } from 'react-native';
import PerformanceMonitor from '../services/PerformanceMonitor';
import PerformanceIntelligence from '../services/PerformanceIntelligence';
const screenWidth = Dimensions.get('window').width;
export const PerformanceMonitoringUI: React.FC = () => {
const [performanceData, setPerformanceData] = useState<any>(null);
const [analysis, setAnalysis] = useState<any>(null);
const [isMonitoring, setIsMonitoring] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const performanceMonitor = PerformanceMonitor.getInstance();
const performanceAI = new PerformanceIntelligence('your-openai-api-key');
useEffect(() => {
loadPerformanceData();
startMonitoring();
return () => {
performanceMonitor.stopMonitoring();
};
}, []);
const startMonitoring = async () => {
await performanceMonitor.startMonitoring();
setIsMonitoring(true);
};
const loadPerformanceData = async () => {
try {
const data = await performanceMonitor.getPerformanceReport();
setPerformanceData(data);
const analysisResult = await performanceAI.analyzeAppPerformance();
setAnalysis(analysisResult);
} catch (error) {
console.error('Error loading performance data:', error);
}
};
const handleRefresh = async () => {
setRefreshing(true);
await loadPerformanceData();
setRefreshing(false);
};
const handleOptimize = async () => {
Alert.alert(
'Auto-Optimize',
'Run automated performance optimizations?',
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Optimize',
onPress: async () => {
try {
const results = await performanceAI.runAutomatedOptimizations();
Alert.alert(
'Optimization Complete',
`Applied ${results.applied} optimizations, ${results.failed} failed.`
);
await loadPerformanceData();
} catch (error) {
Alert.alert('Error', 'Failed to run optimizations');
}
}
}
]
);
};
const getScoreColor = (score: number) => {
if (score >= 80) return '#34C759';
if (score >= 60) return '#FF9500';
return '#FF3B30';
};
const getSeverityIcon = (severity: string) => {
switch (severity) {
case 'critical': return 'alert-circle';
case 'high': return 'warning';
case 'medium': return 'information-circle';
default: return 'checkmark-circle';
}
};
if (!performanceData || !analysis) {
return (
<View style={styles.loadingContainer}>
<Text>Loading performance data...</Text>
</View>
);
}
// Prepare chart data
const memoryChartData = {
labels: performanceData.memoryTrend.slice(-6).map((_: any, i: number) => `${i * 10}s`),
datasets: [{
data: performanceData.memoryTrend.slice(-6).map((m: any) => Math.round(m.used / 1024 / 1024)),
color: () => '#007AFF',
strokeWidth: 2,
}],
};
return (
<ScrollView style={styles.container} refreshing={refreshing} onRefresh={handleRefresh}>
{/* Header */}
<View style={styles.header}>
<Text style={styles.title}>Performance Monitor</Text>
<View style={styles.headerActions}>
<TouchableOpacity
style={[styles.statusButton, isMonitoring ? styles.monitoring : styles.stopped]}
onPress={isMonitoring ? () => {
performanceMonitor.stopMonitoring();
setIsMonitoring(false);
} : startMonitoring}
>
<Ionicons
name={isMonitoring ? 'pause' : 'play'}
size={20}
color="white"
/>
<Text style={styles.statusText}>
{isMonitoring ? 'Stop' : 'Start'}
</Text>
</TouchableOpacity>
</View>
</View>
{/* Overall Score */}
<View style={styles.scoreContainer}>
<View style={styles.overallScore}>
<Text style={[styles.scoreNumber, { color: getScoreColor(analysis.overallScore) }]}>
{analysis.overallScore}
</Text>
<Text style={styles.scoreLabel}>Overall Score</Text>
</View>
<View style={styles.categoryScores}>
{Object.entries(analysis.categories).map(([category, score]: [string, any]) => (
<View key={category} style={styles.categoryScore}>
<Text style={styles.categoryName}>
{category.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())}
</Text>
<View style={styles.scoreBar}>
<View
style={[
styles.scoreBarFill,
{
width: `${score}%`,
backgroundColor: getScoreColor(score)
}
]}
/>
</View>
<Text style={styles.scoreValue}>{score}</Text>
</View>
))}
</View>
</View>
{/* Memory Usage Chart */}
<View style={styles.chartContainer}>
<Text style={styles.chartTitle}>Memory Usage (MB)</Text>
<LineChart
data={memoryChartData}
width={screenWidth - 40}
height={200}
chartConfig={{
backgroundColor: '#FFFFFF',
backgroundGradientFrom: '#FFFFFF',
backgroundGradientTo: '#FFFFFF',
decimalPlaces: 0,
color: (opacity = 1) => `rgba(0, 122, 255, ${opacity})`,
labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
style: {
borderRadius: 16,
},
}}
style={styles.chart}
/>
</View>
{/* Critical Issues */}
{analysis.criticalIssues.length > 0 && (
<View style={styles.issuesContainer}>
<Text style={styles.sectionTitle}>Critical Issues</Text>
{analysis.criticalIssues.map((issue: any, index: number) => (
<View key={index} style={styles.issueItem}>
<View style={styles.issueHeader}>
<Ionicons
name={getSeverityIcon(issue.severity)}
size={20}
color={issue.severity === 'critical' ? '#FF3B30' : issue.severity === 'high' ? '#FF9500' : '#007AFF'}
/>
<Text style={styles.issueTitle}>{issue.type.toUpperCase()}</Text>
<View style={[styles.severityBadge, { backgroundColor:
issue.severity === 'critical' ? '#FF3B30' :
issue.severity === 'high' ? '#FF9500' : '#007AFF'
}]}>
<Text style={styles.severityText}>{issue.severity}</Text>
</View>
</View>
<Text style={styles.issueDescription}>{issue.description}</Text>
<Text style={styles.issueSolution}>{issue.solution}</Text>
<Text style={styles.issueImpact}>Impact: {issue.estimatedImpact}</Text>
</View>
))}
</View>
)}
{/* Optimization Plan */}
<View style={styles.optimizationContainer}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>Optimization Plan</Text>
<TouchableOpacity style={styles.optimizeButton} onPress={handleOptimize}>
<Ionicons name="flash" size={16} color="white" />
<Text style={styles.optimizeButtonText}>Auto-Optimize</Text>
</TouchableOpacity>
</View>
{analysis.optimizationPlan.map((item: any, index: number) => (
<View key={index} style={styles.optimizationItem}>
<View style={styles.optimizationHeader}>
<View style={styles.priorityBadge}>
<Text style={styles.priorityText}>#{item.priority}</Text>
</View>
<Text style={styles.optimizationAction}>{item.action}</Text>
</View>
<Text style={styles.optimizationImprovement}>{item.expectedImprovement}</Text>
<View style={styles.effortBadge}>
<Text style={styles.effortText}>Effort: {item.implementationEffort}</Text>
</View>
</View>
))}
</View>
{/* Performance Summary */}
<View style={styles.summaryContainer}>
<Text style={styles.sectionTitle}>Performance Summary</Text>
<View style={styles.summaryGrid}>
<View style={styles.summaryItem}>
<Text style={styles.summaryValue}>
{performanceData.summary.averageRenderTime.toFixed(1)}ms
</Text>
<Text style={styles.summaryLabel}>Avg Render Time</Text>
</View>
<View style={styles.summaryItem}>
<Text style={styles.summaryValue}>
{performanceData.summary.totalFrameDrops}
</Text>
<Text style={styles.summaryLabel}>Frame Drops</Text>
</View>
<View style={styles.summaryItem}>
<Text style={styles.summaryValue}>
{Math.round(performanceData.summary.averageMemoryUsage / 1024 / 1024)}MB
</Text>
<Text style={styles.summaryLabel}>Memory Usage</Text>
</View>
<View style={styles.summaryItem}>
<Text style={styles.summaryValue}>
{performanceData.summary.criticalIssues}
</Text>
<Text style={styles.summaryLabel}>Critical Issues</Text>
</View>
</View>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F8F9FA',
},
loadingContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
header: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 20,
backgroundColor: 'white',
borderBottomWidth: 1,
borderBottomColor: '#E5E5E7',
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: '#000',
},
headerActions: {
flexDirection: 'row',
gap: 12,
},
statusButton: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 8,
gap: 6,
},
monitoring: {
backgroundColor: '#FF3B30',
},
stopped: {
backgroundColor: '#34C759',
},
statusText: {
color: 'white',
fontWeight: '600',
},
scoreContainer: {
backgroundColor: 'white',
margin: 20,
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
overallScore: {
alignItems: 'center',
marginBottom: 24,
},
scoreNumber: {
fontSize: 48,
fontWeight: 'bold',
},
scoreLabel: {
fontSize: 16,
color: '#8E8E93',
marginTop: 4,
},
categoryScores: {
gap: 16,
},
categoryScore: {
flexDirection: 'row',
alignItems: 'center',
gap: 12,
},
categoryName: {
fontSize: 14,
fontWeight: '500',
flex: 1,
},
scoreBar: {
width: 100,
height: 8,
backgroundColor: '#E5E5E7',
borderRadius: 4,
overflow: 'hidden',
},
scoreBarFill: {
height: '100%',
borderRadius: 4,
},
scoreValue: {
fontSize: 14,
fontWeight: '600',
minWidth: 30,
textAlign: 'right',
},
chartContainer: {
backgroundColor: 'white',
margin: 20,
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
chartTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 16,
color: '#000',
},
chart: {
borderRadius: 8,
},
issuesContainer: {
backgroundColor: 'white',
margin: 20,
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
marginBottom: 16,
color: '#000',
},
sectionHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
issueItem: {
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: '#F0F0F0',
},
issueHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
marginBottom: 8,
},
issueTitle: {
fontSize: 14,
fontWeight: '600',
flex: 1,
},
severityBadge: {
paddingHorizontal: 8,
paddingVertical: 2,
borderRadius: 4,
},
severityText: {
color: 'white',
fontSize: 12,
fontWeight: '600',
},
issueDescription: {
fontSize: 14,
color: '#333',
marginBottom: 4,
},
issueSolution: {
fontSize: 14,
color: '#007AFF',
marginBottom: 4,
},
issueImpact: {
fontSize: 12,
color: '#8E8E93',
},
optimizationContainer: {
backgroundColor: 'white',
margin: 20,
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
optimizeButton: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#007AFF',
paddingHorizontal: 12,
paddingVertical: 6,
borderRadius: 6,
gap: 4,
},
optimizeButtonText: {
color: 'white',
fontSize: 14,
fontWeight: '600',
},
optimizationItem: {
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: '#F0F0F0',
},
optimizationHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
marginBottom: 8,
},
priorityBadge: {
backgroundColor: '#007AFF',
width: 24,
height: 24,
borderRadius: 12,
justifyContent: 'center',
alignItems: 'center',
},
priorityText: {
color: 'white',
fontSize: 12,
fontWeight: '600',
},
optimizationAction: {
fontSize: 14,
fontWeight: '500',
flex: 1,
},
optimizationImprovement: {
fontSize: 14,
color: '#34C759',
marginBottom: 4,
},
effortBadge: {
alignSelf: 'flex-start',
},
effortText: {
fontSize: 12,
color: '#8E8E93',
},
summaryContainer: {
backgroundColor: 'white',
margin: 20,
padding: 20,
borderRadius: 12,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
summaryGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 16,
},
summaryItem: {
flex: 1,
minWidth: '45%',
alignItems: 'center',
padding: 12,
backgroundColor: '#F8F9FA',
borderRadius: 8,
},
summaryValue: {
fontSize: 20,
fontWeight: 'bold',
color: '#007AFF',
},
summaryLabel: {
fontSize: 12,
color: '#8E8E93',
textAlign: 'center',
marginTop: 4,
},
});
export default PerformanceMonitoringUI;
In this lesson, you learned:
Code with AI: Try building these advanced performance features.
Prompts to try:
Great performance is invisible to users but crucial for success - invest in getting it right from day one!