235 lines
7.1 KiB
JavaScript
235 lines
7.1 KiB
JavaScript
|
|
/**
|
||
|
|
* Performance-Optimized Application Initializer
|
||
|
|
* Loads critical resources first, then defers non-critical scripts
|
||
|
|
*/
|
||
|
|
(function () {
|
||
|
|
"use strict";
|
||
|
|
|
||
|
|
// ============================================================
|
||
|
|
// CRITICAL PATH - Load immediately
|
||
|
|
// ============================================================
|
||
|
|
|
||
|
|
// Performance monitoring
|
||
|
|
const perfMarks = {
|
||
|
|
scriptStart: performance.now(),
|
||
|
|
domReady: 0,
|
||
|
|
imagesLoaded: 0,
|
||
|
|
appInitialized: 0,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Optimized lazy image loader initialization
|
||
|
|
let lazyLoader = null;
|
||
|
|
|
||
|
|
function initLazyLoading() {
|
||
|
|
if (
|
||
|
|
window.PerformanceUtils &&
|
||
|
|
window.PerformanceUtils.OptimizedLazyLoader
|
||
|
|
) {
|
||
|
|
lazyLoader = new window.PerformanceUtils.OptimizedLazyLoader({
|
||
|
|
rootMargin: "100px",
|
||
|
|
threshold: 0.01,
|
||
|
|
});
|
||
|
|
console.log("[Performance] Lazy loading initialized");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Resource hints for external resources
|
||
|
|
function addResourceHints() {
|
||
|
|
if (window.PerformanceUtils && window.PerformanceUtils.ResourceHints) {
|
||
|
|
// Preconnect to CDNs (if used)
|
||
|
|
window.PerformanceUtils.ResourceHints.addPreconnect([
|
||
|
|
"https://cdn.jsdelivr.net",
|
||
|
|
"https://fonts.googleapis.com",
|
||
|
|
"https://fonts.gstatic.com",
|
||
|
|
]);
|
||
|
|
console.log("[Performance] Resource hints added");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Debounced scroll handler
|
||
|
|
let scrollHandler = null;
|
||
|
|
function initOptimizedScrollHandlers() {
|
||
|
|
if (window.PerformanceUtils && window.PerformanceUtils.rafThrottle) {
|
||
|
|
// Use RAF throttle for smooth 60fps scrolling
|
||
|
|
scrollHandler = window.PerformanceUtils.rafThrottle(() => {
|
||
|
|
// Any scroll-based updates here
|
||
|
|
const scrollTop =
|
||
|
|
window.pageYOffset || document.documentElement.scrollTop;
|
||
|
|
document.body.classList.toggle("scrolled", scrollTop > 50);
|
||
|
|
});
|
||
|
|
|
||
|
|
window.addEventListener("scroll", scrollHandler, { passive: true });
|
||
|
|
console.log("[Performance] Optimized scroll handler attached");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Event delegation for better memory management
|
||
|
|
let eventDelegator = null;
|
||
|
|
function initEventDelegation() {
|
||
|
|
if (window.PerformanceUtils && window.PerformanceUtils.EventDelegator) {
|
||
|
|
eventDelegator = new window.PerformanceUtils.EventDelegator();
|
||
|
|
|
||
|
|
// Delegate all button clicks
|
||
|
|
eventDelegator.on("click", "button[data-action]", function (e) {
|
||
|
|
const action = this.dataset.action;
|
||
|
|
const event = new CustomEvent("app:action", {
|
||
|
|
detail: { action, element: this },
|
||
|
|
bubbles: true,
|
||
|
|
});
|
||
|
|
document.dispatchEvent(event);
|
||
|
|
});
|
||
|
|
|
||
|
|
console.log("[Performance] Event delegation initialized");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// DOM Batcher for efficient updates
|
||
|
|
let domBatcher = null;
|
||
|
|
function initDOMBatcher() {
|
||
|
|
if (window.PerformanceUtils && window.PerformanceUtils.DOMBatcher) {
|
||
|
|
domBatcher = new window.PerformanceUtils.DOMBatcher();
|
||
|
|
window.AppState = window.AppState || {};
|
||
|
|
window.AppState.domBatcher = domBatcher;
|
||
|
|
console.log("[Performance] DOM batcher initialized");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================
|
||
|
|
// INITIALIZATION SEQUENCE
|
||
|
|
// ============================================================
|
||
|
|
|
||
|
|
function onDOMReady() {
|
||
|
|
perfMarks.domReady = performance.now();
|
||
|
|
console.log(
|
||
|
|
`[Performance] DOM ready in ${(
|
||
|
|
perfMarks.domReady - perfMarks.scriptStart
|
||
|
|
).toFixed(2)}ms`
|
||
|
|
);
|
||
|
|
|
||
|
|
// Add resource hints immediately
|
||
|
|
addResourceHints();
|
||
|
|
|
||
|
|
// Initialize performance utilities
|
||
|
|
initLazyLoading();
|
||
|
|
initOptimizedScrollHandlers();
|
||
|
|
initEventDelegation();
|
||
|
|
initDOMBatcher();
|
||
|
|
|
||
|
|
// Initialize main app (if loaded)
|
||
|
|
if (window.AppState && typeof window.AppState.init === "function") {
|
||
|
|
window.AppState.init();
|
||
|
|
perfMarks.appInitialized = performance.now();
|
||
|
|
console.log(
|
||
|
|
`[Performance] App initialized in ${(
|
||
|
|
perfMarks.appInitialized - perfMarks.domReady
|
||
|
|
).toFixed(2)}ms`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Monitor when all images are loaded
|
||
|
|
if (document.images.length > 0) {
|
||
|
|
Promise.all(
|
||
|
|
Array.from(document.images)
|
||
|
|
.filter((img) => !img.complete)
|
||
|
|
.map(
|
||
|
|
(img) =>
|
||
|
|
new Promise((resolve) => {
|
||
|
|
img.addEventListener("load", resolve);
|
||
|
|
img.addEventListener("error", resolve);
|
||
|
|
})
|
||
|
|
)
|
||
|
|
).then(() => {
|
||
|
|
perfMarks.imagesLoaded = performance.now();
|
||
|
|
console.log(
|
||
|
|
`[Performance] All images loaded in ${(
|
||
|
|
perfMarks.imagesLoaded - perfMarks.domReady
|
||
|
|
).toFixed(2)}ms`
|
||
|
|
);
|
||
|
|
reportPerformanceMetrics();
|
||
|
|
});
|
||
|
|
} else {
|
||
|
|
perfMarks.imagesLoaded = performance.now();
|
||
|
|
reportPerformanceMetrics();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function onWindowLoad() {
|
||
|
|
console.log(
|
||
|
|
`[Performance] Window fully loaded in ${(
|
||
|
|
performance.now() - perfMarks.scriptStart
|
||
|
|
).toFixed(2)}ms`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Report performance metrics
|
||
|
|
function reportPerformanceMetrics() {
|
||
|
|
if (!window.performance || !window.performance.timing) return;
|
||
|
|
|
||
|
|
const timing = performance.timing;
|
||
|
|
const metrics = {
|
||
|
|
// Page load metrics
|
||
|
|
domContentLoaded:
|
||
|
|
timing.domContentLoadedEventEnd - timing.navigationStart,
|
||
|
|
windowLoad: timing.loadEventEnd - timing.navigationStart,
|
||
|
|
|
||
|
|
// Network metrics
|
||
|
|
dns: timing.domainLookupEnd - timing.domainLookupStart,
|
||
|
|
tcp: timing.connectEnd - timing.connectStart,
|
||
|
|
request: timing.responseStart - timing.requestStart,
|
||
|
|
response: timing.responseEnd - timing.responseStart,
|
||
|
|
|
||
|
|
// Rendering metrics
|
||
|
|
domProcessing: timing.domComplete - timing.domLoading,
|
||
|
|
|
||
|
|
// Script metrics
|
||
|
|
scriptExecution: perfMarks.appInitialized - perfMarks.scriptStart,
|
||
|
|
imageLoading: perfMarks.imagesLoaded - perfMarks.domReady,
|
||
|
|
|
||
|
|
// Paint metrics (if available)
|
||
|
|
firstPaint: null,
|
||
|
|
firstContentfulPaint: null,
|
||
|
|
};
|
||
|
|
|
||
|
|
// Get paint metrics
|
||
|
|
if (window.performance && window.performance.getEntriesByType) {
|
||
|
|
const paintEntries = performance.getEntriesByType("paint");
|
||
|
|
paintEntries.forEach((entry) => {
|
||
|
|
if (entry.name === "first-paint") {
|
||
|
|
metrics.firstPaint = entry.startTime;
|
||
|
|
} else if (entry.name === "first-contentful-paint") {
|
||
|
|
metrics.firstContentfulPaint = entry.startTime;
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
console.table(metrics);
|
||
|
|
|
||
|
|
// Store for analytics (if needed)
|
||
|
|
window.performanceMetrics = metrics;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ============================================================
|
||
|
|
// EVENT LISTENERS
|
||
|
|
// ============================================================
|
||
|
|
|
||
|
|
if (document.readyState === "loading") {
|
||
|
|
document.addEventListener("DOMContentLoaded", onDOMReady);
|
||
|
|
} else {
|
||
|
|
// DOM already loaded
|
||
|
|
setTimeout(onDOMReady, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
window.addEventListener("load", onWindowLoad);
|
||
|
|
|
||
|
|
// Cleanup on page unload
|
||
|
|
window.addEventListener("beforeunload", () => {
|
||
|
|
if (lazyLoader) lazyLoader.destroy();
|
||
|
|
if (scrollHandler) window.removeEventListener("scroll", scrollHandler);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Export performance marks for debugging
|
||
|
|
window.perfMarks = perfMarks;
|
||
|
|
|
||
|
|
console.log("[Performance] Optimized initializer loaded");
|
||
|
|
})();
|