UNPKG

html2canvas-pro

Version:

Screenshots with JavaScript. Next generation!

208 lines 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NoOpPerformanceMonitor = exports.PerformanceMonitor = void 0; /** * Performance Monitor * * Tracks performance metrics throughout the rendering pipeline. * Provides insights into where time is spent during rendering. * * Usage: * ```typescript * const monitor = new PerformanceMonitor(context); * * monitor.start('clone'); * await cloneDocument(); * monitor.end('clone'); * * const summary = monitor.getSummary(); * ``` */ class PerformanceMonitor { constructor(context, enabled = true) { this.context = context; this.activeMetrics = new Map(); this.completedMetrics = []; this.enabled = enabled; // Fallback for environments without performance.now() this.getTime = typeof performance !== 'undefined' && typeof performance.now === 'function' ? () => performance.now() : () => Date.now(); } /** * Start measuring a performance metric * * @param name - Unique name for this metric * @param metadata - Optional metadata to attach */ start(name, metadata) { if (!this.enabled) { return; } if (this.activeMetrics.has(name)) { this.context?.logger.warn(`Performance metric '${name}' already started. Overwriting.`); } this.activeMetrics.set(name, { name, startTime: this.getTime(), metadata }); } /** * End measuring a performance metric * * @param name - Name of the metric to end * @returns The completed metric, or undefined if not found */ end(name) { if (!this.enabled) { return undefined; } const metric = this.activeMetrics.get(name); if (!metric) { this.context?.logger.warn(`Performance metric '${name}' not found. Was start() called?`); return undefined; } metric.endTime = this.getTime(); metric.duration = metric.endTime - metric.startTime; this.completedMetrics.push(metric); this.activeMetrics.delete(name); this.context?.logger.debug(`⏱️ ${name}: ${metric.duration.toFixed(2)}ms`, metric.metadata); return metric; } /** * Measure a synchronous function * * @param name - Name for this measurement * @param fn - Function to measure * @param metadata - Optional metadata * @returns The function's return value */ measure(name, fn, metadata) { this.start(name, metadata); try { const result = fn(); this.end(name); return result; } catch (error) { this.end(name); throw error; } } /** * Measure an asynchronous function * * @param name - Name for this measurement * @param fn - Async function to measure * @param metadata - Optional metadata * @returns Promise resolving to the function's return value */ async measureAsync(name, fn, metadata) { this.start(name, metadata); try { const result = await fn(); this.end(name); return result; } catch (error) { this.end(name); throw error; } } /** * Get all completed metrics * * @returns Array of completed performance metrics */ getMetrics() { return [...this.completedMetrics]; } /** * Get a specific metric by name * * @param name - Metric name * @returns The metric, or undefined if not found */ getMetric(name) { return this.completedMetrics.find((m) => m.name === name); } /** * Get performance summary * * @returns Aggregated performance data */ getSummary() { const totalDuration = this.completedMetrics.reduce((sum, metric) => sum + (metric.duration || 0), 0); const breakdown = this.completedMetrics.map((metric) => ({ name: metric.name, duration: metric.duration || 0, percentage: totalDuration > 0 ? (((metric.duration || 0) / totalDuration) * 100).toFixed(1) + '%' : '0%' })); return { totalDuration, metrics: this.getMetrics(), breakdown }; } /** * Log performance summary to console */ logSummary() { if (!this.enabled || this.completedMetrics.length === 0 || !this.context) { return; } const summary = this.getSummary(); this.context.logger.info(`\n📊 Performance Summary (Total: ${summary.totalDuration.toFixed(2)}ms):`); summary.breakdown .sort((a, b) => b.duration - a.duration) .forEach((item) => { this.context.logger.info(` ${item.name.padEnd(20)} ${item.duration.toFixed(2).padStart(8)}ms ${item.percentage.padStart(6)}`); }); } /** * Clear all metrics */ clear() { this.activeMetrics.clear(); this.completedMetrics.splice(0); } /** * Check if monitoring is enabled */ isEnabled() { return this.enabled; } /** * Get active (uncompleted) metrics * Useful for debugging leaked measurements */ getActiveMetrics() { return Array.from(this.activeMetrics.keys()); } } exports.PerformanceMonitor = PerformanceMonitor; /** * Create a no-op performance monitor for production * Has minimal overhead when disabled */ class NoOpPerformanceMonitor extends PerformanceMonitor { constructor() { super(null, false); } start() { // No-op } end() { return undefined; } measure(_name, fn) { return fn(); } async measureAsync(_name, fn) { return await fn(); } } exports.NoOpPerformanceMonitor = NoOpPerformanceMonitor; //# sourceMappingURL=performance-monitor.js.map