速度一直是 Hexo 的关键。3 年前,Hexo 3.2 通过模板预编译将生成速度提高了 2 倍。现在我们已经到了 Hexo 4.2,通过多项性能改进,我们成功地将生成速度提高了 30%,与 Hexo 3.2 相比。
基准测试
以下是基准测试的设置方式
- Travis CI - Ubuntu Xenial 16.04
- CPU:2 核
- RAM:7.5 GB
- Hexo 默认主题:landscape
- 300 个随机生成的帖子。每个帖子都包含所有常用的 Markdown 语法和用于测试
highlight.js
的代码块。还为这些帖子的前端物质设置了唯一的类别和三个标签。
自 Hexo 3.2 以来,渲染后的内容将被缓存到 warehouse
(db.json
)中,因此在基准测试中测试了冷生成(hexo clean
之前 hexo g
)和热生成(没有 hexo clean
)的性能。每个基准测试都是通过 Cold => Hot => Cold
执行的。内存使用量是使用 time
测量的,并将采用驻留集大小 (RSS) 的值。
您可以在此处找到基准测试脚本:这里。
Node.js 8
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
冷处理 | 13.585 秒 | 0% | 18.572 秒 | +37% | 9.210 秒 | -32% |
冷生成 | 13.027 秒 | 0% | 50.528 秒 | +284% | 8.666 秒 | -33% |
内存使用量 (冷) | 815.754 MB | 0% | 1416.309 MB | +69% | 605.312 MB | -26% |
热处理 | 0.668 秒 | 0% | 0.712 秒 | +6% | 0.732 秒 | +7% |
热生成 | 11.734 秒 | 0% | 46.339 秒 | +295% | 7.821 秒 | -33% |
内存使用量 (热) | 702.535 MB | 0% | 1450.719 MB | +106% | 821.512 MB | +17% |
Node.js 10
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
冷处理 | 11.875 秒 | 0% | 15.985 秒 | +35% | 8.043 秒 | -29% |
冷生成 | 10.308 秒 | 0% | 41.339 秒 | +301% | 7.450 秒 | -28% |
内存使用量 (冷) | 805.633 MB | 0% | 1440.297 MB | +79% | 599.008 MB | -26% |
热处理 | 0.700 秒 | 0% | 0.676 秒 | -3% | 0.731 秒 | +4% |
热生成 | 8.322 秒 | 0% | 35.453 秒 | +326% | 6.420 秒 | -23% |
内存使用量 (热) | 679.082 MB | 0% | 1447.109 MB | +113% | 789.527 MB | +16% |
Node.js 12
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
冷处理 | 11.454 秒 | 0% | 15.626 秒 | +36% | 8.381 秒 | -27% |
冷生成 | 10.428 秒 | 0% | 37.482 秒 | +260% | 7.283 秒 | -30% |
内存使用量 (冷) | 1101.586 MB | 0% | 1413.359 MB | +28% | 580.953 MB | -47% |
热处理 | 0.724 秒 | 0% | 0.790 秒 | +9% | 0.790 秒 | +9% |
热生成 | 8.994 秒 | 0% | 35.116 秒 | +293% | 6.385 秒 | -29% |
内存使用量 (热) | 696.500 MB | 0% | 1538.719 MB | +120% | 600.398 MB | -14% |
Node.js 13
Hexo 3.2 | Hexo 3.8 | Hexo 4.2 | ||||
---|---|---|---|---|---|---|
冷处理 | 11.496 秒 | 0% | 14.970 秒 | +29% | 8.489 秒 | -26% |
冷生成 | 10.088 秒 | 0% | 36.867 秒 | +265% | 7.212 秒 | -28% |
内存使用量 (冷) | 1104.465 MB | 0% | 1418.273 MB | +28% | 596.233 MB | -46% |
热处理 | 0.724 秒 | 0% | 0.776 秒 | +7% | 0.756 秒 | +4% |
热生成 | 7.995 秒 | 0% | 33.968 秒 | +325% | 6.294 秒 | -21% |
内存使用量 (热) | 761.195 MB | 0% | 1516.078 MB | +99% | 812.234 MB | +7% |
从 Hexo 中删除 cheerio 依赖
正如您在基准测试结果中看到的那样,Hexo 3.8 中存在严重的性能倒退。事实证明,在 #3129 中引入的 meta_generator
过滤器是罪魁祸首。#3129 使用 cheerio
将 <meta name = "generator" content = "Hexo [version]">
插入到 <head>
中,因此 cheerio
必须将 Hexo 生成的所有 HTML 加载到内存中并解析为 DOM。
cheerio
很快,但遍历数百个 HTML 文件时仍然会出现性能瓶颈。在 #3677 中,我们提出了用原生 API 替换 cheerio
的建议。在 #3671、#3680 和 #3685 中,我们将 cheerio
用正则表达式替换为 open_graph()
帮助程序、meta_generator
过滤器和 external_link
过滤器,在 hexo-util#137 和 #3850 中,我们将 cheerio
用更快的 htmlparser2
替换。现在,我们在 Hexo 4.2 中完全删除了 cheerio
。
改进 渲染后的 HTML 缓存
机制
渲染后的 HTML 缓存
是在 Hexo 3.0.0-rc4 中引入的 (e8e45ed
),它旨在通过缓存渲染结果来提高 Hexo 的生成性能。但是,每个路由在 hexo g
期间只使用一次,因此会消耗内存,而没有获得性能提升。在 #3756 中,渲染后的 HTML 缓存
被禁用以用于 hexo g
,并启用以用于 hexo s
,因此 hexo g
的内存使用量已减少。
从 Hexo 中删除 Lodash 依赖
Lodash 是一个现代的 JavaScript 实用程序库,它使处理数组、数字、对象和字符串变得更加容易。但是,随着 ES6 中越来越多的新功能引入,Lodash 的大多数功能都可以用原生 JavaScript 替换。
Hexo 实际上在一年前就开始减少 Lodash 的依赖,例如 #3285、#3290 和 warehouse#18。在 #3753 中,我们建议通过遵循 您(可能)不需要 Lodash/Underscore 来逐步用原生 JavaScript 替换 Lodash。在 #3785、#3786、#3788、#3790、#3791、#3809、#3810、#3813、#3826、#3845、hexo-util#141、#3880 和 #3969 之后,我们成功地从 Hexo 中删除了 Lodash。我们还在 您(可能)不需要 Lodash/Underscore 中打开了一个新的 PR,将我们的 _.assignIn
替代方案带回社区。
缓存实用程序函数的返回值
在 hexo-util
中有很多实用程序,例如用于计算相对路径的 relative_url(from, to)
,用于将相对路径转换为 URL 的 url_for(path)
和 full_url_for(path)
,用于从电子邮件地址计算 Gravatar URL 的 gravatar(mail)
,以及用于确定给定 URL 是否为外部链接的 isExternalLink(url)
。我们发现这些函数可能在 Hexo 生成过程中被调用数千次,而相同的参数可能会重复传递,因此可以缓存参数的键值和返回值。该想法是在 hexo-util#162 中实现的。
未来
我们在 #3776 中将基准测试添加到了 CI 中,作为单元测试的一部分。从那时起,基准测试帮助我们多次发现潜在的性能倒退(例如 #3807 和 #3833)并避免了像 #3129 这样的严重性能倒退。我们将在 #4000 中更进一步,将火焰图添加到单元测试用例中,这将帮助我们更好地优化 Hexo 的生成过程。对于 Hexo 来说,速度一直是关键。