perf(about): 优化页面初始化和渲染性能

- 使用requestIdleCallback优化初始数据获取时机
- 降级方案使用延迟setTimeout避免阻塞主线程
- 引入requestAnimationFrame优化DOM更新避免强制重排
- 为3D球体添加防抖尺寸计算和批量样式更新
- 监听窗口resize事件动态调整3D球体布局
- 添加主题/语言变更的日志记录便于调试
This commit is contained in:
hehh
2025-11-25 10:41:11 +08:00
parent 823d397f12
commit 79c79bf864

View File

@@ -220,8 +220,15 @@ class DataManager {
} }
init() { init() {
setTimeout(() => this.fetchGithub(), 0); // 使用requestIdleCallback或setTimeout优化初始化调用
setTimeout(() => this.fetchBlog(), 0); if ('requestIdleCallback' in window) {
requestIdleCallback(() => this.fetchGithub(), { timeout: 1000 });
requestIdleCallback(() => this.fetchBlog(), { timeout: 1000 });
} else {
// 降级到setTimeout但稍后执行以避免阻塞
setTimeout(() => this.fetchGithub(), 50);
setTimeout(() => this.fetchBlog(), 100);
}
} }
// 创建带超时的fetch函数 // 创建带超时的fetch函数
@@ -336,10 +343,16 @@ class DataManager {
<div class="repo-desc">${escapeHtml(dShort)}</div> <div class="repo-desc">${escapeHtml(dShort)}</div>
</div>`; </div>`;
}); });
// 使用requestAnimationFrame避免强制重排
requestAnimationFrame(() => {
const pc = $('#projects-container'); const pc = $('#projects-container');
pc.removeClass('fade-in'); pc.removeClass('fade-in');
requestAnimationFrame(() => {
pc.html(html); pc.html(html);
pc.addClass('fade-in'); pc.addClass('fade-in');
});
});
} }
// 从RSS获取博客文章 // 从RSS获取博客文章
@@ -447,10 +460,16 @@ class DataManager {
<div class="b-cat">${escapeHtml(cat)}</div> <div class="b-cat">${escapeHtml(cat)}</div>
</div>`; </div>`;
}); });
// 使用requestAnimationFrame避免强制重排
requestAnimationFrame(() => {
const bc = $('#blog-container'); const bc = $('#blog-container');
bc.removeClass('fade-in'); bc.removeClass('fade-in');
requestAnimationFrame(() => {
bc.html(html); bc.html(html);
bc.addClass('fade-in'); bc.addClass('fade-in');
});
});
} }
} }
@@ -585,6 +604,7 @@ class UIManager {
const themeObserver = new MutationObserver(() => { const themeObserver = new MutationObserver(() => {
const newTheme = document.documentElement.getAttribute('data-theme'); const newTheme = document.documentElement.getAttribute('data-theme');
const newLang = document.documentElement.getAttribute('data-lang'); const newLang = document.documentElement.getAttribute('data-lang');
console.log('Theme/Language changed:', newTheme, newLang);
// 延迟执行 // 延迟执行
setTimeout(() => { setTimeout(() => {
// 重新加载整个评论组件 // 重新加载整个评论组件
@@ -738,7 +758,28 @@ class UIManager {
} else { } else {
// PC: 3D Sphere // PC: 3D Sphere
container.classList.remove('mobile-scroll'); container.classList.remove('mobile-scroll');
container.__animToken = Date.now();
// 使用防抖优化尺寸计算
let resizeTimeout;
const updateContainerSize = () => {
if (resizeTimeout) {
clearTimeout(resizeTimeout);
}
resizeTimeout = setTimeout(() => {
init3DSphere();
}, 100);
};
// 初始化3D球体
const init3DSphere = () => {
// 清除之前的动画
if (container.__animToken) {
cancelAnimationFrame(container.__animToken);
}
// 清空容器
container.innerHTML = '';
const tags = []; const tags = [];
techStack.forEach((item, index) => { techStack.forEach((item, index) => {
@@ -752,13 +793,13 @@ class UIManager {
tags.push({el, x: 0, y: 0, z: 0}); tags.push({el, x: 0, y: 0, z: 0});
}); });
// 动态半径,避免容器溢出 // 动态半径,避免容器溢出,使用防抖优化
let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24); let radius = Math.max(160, Math.min(container.offsetWidth, container.offsetHeight) / 2 - 24);
const dtr = Math.PI / 180; const dtr = Math.PI / 180;
let lasta = 1, lastb = 1; let lasta = 1, lastb = 1;
let active = false, mouseX = 0, mouseY = 0; let active = false, mouseX = 0, mouseY = 0;
// Init positions // 初始化位置
tags.forEach((tag, i) => { tags.forEach((tag, i) => {
let phi = Math.acos(-1 + (2 * i + 1) / tags.length); let phi = Math.acos(-1 + (2 * i + 1) / tags.length);
let theta = Math.sqrt(tags.length * Math.PI) * phi; let theta = Math.sqrt(tags.length * Math.PI) * phi;
@@ -792,6 +833,9 @@ class UIManager {
let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr); let sa = Math.sin(a * dtr), ca = Math.cos(a * dtr);
let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr); let sb = Math.sin(b * dtr), cb = Math.cos(b * dtr);
// 批量更新样式以减少重排
const fragment = document.createDocumentFragment();
tags.forEach(tag => { tags.forEach(tag => {
let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca; let rx1 = tag.x, ry1 = tag.y * ca - tag.z * sa, rz1 = tag.y * sa + tag.z * ca;
let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb; let ry2 = ry1, rz2 = rx1 * -sb + rz1 * cb;
@@ -807,9 +851,18 @@ class UIManager {
let top = tag.y + container.offsetHeight / 2 - tag.el.offsetHeight / 2; let top = tag.y + container.offsetHeight / 2 - tag.el.offsetHeight / 2;
tag.el.style.transform = `translate(${left}px, ${top}px) scale(${scale})`; tag.el.style.transform = `translate(${left}px, ${top}px) scale(${scale})`;
}); });
requestAnimationFrame(update);
container.__animToken = requestAnimationFrame(update);
}; };
update();
container.__animToken = requestAnimationFrame(update);
};
// 初始化3D球体
init3DSphere();
// 监听窗口大小变化
window.addEventListener('resize', updateContainerSize);
} }
} }