【问题解决】个人博客加载速度优化
- 破浪(遇到的bug及解决方案)
- 2025-06-12
- 32热度
- 0评论
前言
我的个人 hexo 博客地址:https://jingqing3948.github.io . 之前感觉启动加载特别特别慢,得 10s 左右,但是看其他人的 hexo 博客加载都比较快。然后我就总感觉不知道是我部署在 github pages 上的问题,还是图床用 github 仓库的问题,还是主题性能比较差的问题……后来发现其实是自己的配置问题,哈哈。
现在基本能在 3s 内完成加载了,虽然我不完全记得做了哪些具体优化,但是整个问题解决的思路是有的,所以也能总结很多经验,希望可以帮助到开发个人博客的朋友们!
优化思路
首先怎么判断哪些项加载太耗时了?
在自己的网站页面(部署的网站地址 https://xxx.github.io,或者自己的网站域名,或者本地部署预览 localhost:4000),打开开发者模式(F12 或 Ctrl + Shift + C)查看 Network 网络页面的具体加载时间,点两下时间按时间倒序排序:

如图,这里(我已经优化完成的结果)按时间倒序排序,最长的一个是 busuanzi 什么的一个东西,占了半秒钟多。这个其实是一个计算网站点击浏览量的插件。(我发现插件基本都会占用很多很多加载时间)

这个东西我还是想保留的。而且比较难懒加载优化,我就不改了。
之前加载花费时间比较多的有:
- twikoo 评论系统(这个我发现其实我压根没用到,我用的是 gitalk 评论系统,但是还是把 twikoo enable 了,浪费很多时间)直接 enable: false 关了。
- gitalk 评论系统:这个加载非常费时间。所以我决定,首先只有部分页面开启,比如首页我就不开启了。我只在 post 也就是文章发布界面开启,判断方式是当前页面 layout 样式是否为 post。 全局搜索后,找到加载 gitalk 的代码在
gitalk.ejs中:
<% if (theme.gitalk.enable && post.comments && page.layout == 'post') { %>
<div class="gitalk" id="gitalk-container"></div>
<!-- 引入 gitalk 的代码 -->
第二步,不是直接一句 <script src="xxx"></script> 就引入了,这样是阻塞加载。而是 DOM 创建后才加载:
<script>
window.addEventListener('DOMContentLoaded', function () {
const gitalkScript = document.createElement('script');
gitalkScript.src = 'https://cdn.staticfile.org/gitalk/1.7.2/gitalk.min.js';
gitalkScript.onload = function () {
const md5Script = document.createElement('script');
md5Script.src = 'https://cdn.staticfile.org/blueimp-md5/2.19.0/js/md5.min.js';
md5Script.onload = function () {
const gitalk = new Gitalk({ ... });
gitalk.render('gitalk-container');
};
document.body.appendChild(md5Script);
};
document.body.appendChild(gitalkScript);
});
</script>
也就是说,gitalk 没加载完,就可以展示页面了。不过我的文章长度一般都不会只有一页,所以第一眼就出现底部 gitalk 评论模块的页面没有。这样优化完全没问题。
- mermaid 和 mathjax:一样,尝试判断页面中是否有这两个元素才加载。下面是 mermaid 部分加载且懒加载的机制,部分加载是判断渲染后有无 pre class = "mermaid" 的类(这个对应元素名可以去开发者模式看 HTML 源码找到):
<% if (page.content && page.content.includes('<pre class="mermaid"')) { %>
<script>
// 动态加载 Mermaid 脚本并初始化
function loadMermaid(callback) {
const script = document.createElement('script');
script.src = '<%= theme.mermaid.cdn %>';
script.defer = true; // 非阻塞加载
script.onload = callback;
document.body.appendChild(script);
}
// Mermaid 渲染逻辑
const rerenderMermaid = () => {
const isDark = document.body.classList.contains('darkmode');
const theme = isDark ? 'dark' : 'default';
if (!window.mermaid) return;
mermaid.initialize({
startOnLoad: false,
theme,
themeVariables: {
background: 'transparent',
primaryColor: isDark ? '#1e1e1e' : '#ffffff',
primaryTextColor: isDark ? '#d6e4f0' : '#1e1e1e',
noteBkgColor: isDark ? '#2a3b4d' : '#f4f4f4',
noteTextColor: isDark ? '#cddbf5' : '#333',
lineColor: isDark ? '#ffffff' : '#333333',
textColor: isDark ? '#ffffff' : '#000000'
}
});
document.querySelectorAll('.mermaid').forEach((el) => {
if (!el.dataset.code) el.dataset.code = el.textContent;
el.removeAttribute('data-processed');
el.innerHTML = el.dataset.code;
});
mermaid.init(undefined, document.querySelectorAll('.mermaid'));
};
// 页面加载后执行懒加载
document.addEventListener('DOMContentLoaded', () => {
loadMermaid(rerenderMermaid);
});
// 主题切换时重新渲染(注意也需确保 Mermaid 已加载)
document.getElementById('todark')?.addEventListener('click', () => {
setTimeout(() => {
if (window.mermaid && document.querySelector('.mermaid')) {
rerenderMermaid();
}
}, 200);
});
</script>
<% } %>
而且我还可以在其中自行修改样式!我的主页有一个切换浅色深色模式按钮,flag 变量是 darkmode,我可以用这个去改具体的 mermaid 的颜色。
- 公式的判别比较难,GPT 给我一种思路是说判断有无形如
$$ ... $$的公式块。但是我的行内公式是单美元符号包裹,而且我不确定有没有文章是只有行内公式没有公式块的,所以这个选择性渲染 mathjax 公式思路我不敢用,我也没法用懒加载(懒加载是判断有公式才加载,我不确定如何判断)。我做的改进还是只有文章页渲染公式+公式延迟一秒非阻塞渲染。
<% if (page.layout === 'post') { %>
<script>
setTimeout(function () {
window.MathJax = {
tex2jax: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
processEscapes: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
},
showProcessingMessages: false,
messageStyle: 'none',
skipStartupTypeset: false
};
var script = document.createElement('script');
script.src = "https://cdn.staticfile.org/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML";
script.async = true;
document.head.appendChild(script);
}, 1000); // 延迟 1 秒加载
</script>
<% } %>
这里的懒加载和公式判别,如果文章顶端有公式或者流程图,可以看到一瞬间的未渲染源代码,过 1s 后才渲染成流程图和公式形式。不过我觉得问题不大,比阻塞整个页面加载不出来好。
- 图片懒加载:我在 main.js 里加入了全局图片懒加载机制:
document.addEventListener('DOMContentLoaded', () => {
const imgs = document.querySelectorAll('img');
imgs.forEach((img) => {
// 若已是 lazyload 或外链/emoji/logo 则跳过
const src = img.getAttribute('src') || '';
const isAlreadyLazy = img.classList.contains('lazyload');
const isCDN = src.startsWith('http') || src.startsWith('//');
const isSVG = src.endsWith('.svg');
const isLogo = img.closest('header') || img.id === 'logo';
if (!isAlreadyLazy && !isCDN && !isSVG && !isLogo) {
img.setAttribute('data-src', src);
img.removeAttribute('src');
img.classList.add('lazyload');
}
});
});
但是!然后引发了一些问题。我的首页封面是一个轮播图,每次要随机刷新出一个封面。然后懒加载机制会将这个图片的 src 移除,导致首页图片随机刷新出来后突然又消失了。
于是我决定放弃图片懒加载,然后我发现我有一个摄影界面,这个是必须要用懒加载的。Gallery | 灰海宽松的博客 所以也不能全局关掉。
所以,只能局部开启了,至少首页取消图片懒加载机制。
document.addEventListener('DOMContentLoaded', () => {
const path = window.location.pathname;
const isHomePage = path === '/' || path === '/index.html';
if (isHomePage) return; // 首页不懒加载
const imgs = document.querySelectorAll('img');
// ...
});
- 以及,红色的部分是报错,可能也会耗费大量时间。我有一个定义但是没创建的 CSS 文件,加载时也花了一定时间去查找但是没找到。删掉引用就好了。
期待看到大家优化的个人博客!