Yank Note 系列 07 - 性能暴增 132 倍的秘密——重写

Yank Note (opens new window) 是我编写的一款面向程序员的笔记应用。这里我将会写下一些关于 Yank Note 的文章

在之前的文章 Yank Note 系列 02 - Markdown 渲染性能优化之路 中,我描述了为了优化性能而做的努力。不过心里一直有个疙瘩就是文后提到的 markdown-it-attrs (opens new window) 插件性能还是较低。

这个插件我很早就用上了,Yank Note 有不少功能也依赖它。之前也尝试找过类似的插件,都没看到有合适的。

周末天气很冷,要不再看看这个问题吧。

# 重写

Fork 了原作者的代码,发现比较难优化。如下面两行代码复杂度就比较高。

function isArrayOfObjects(arr) {
  return Array.isArray(arr) && arr.length && arr.every(i => typeof i === 'object');
}

function isArrayOfFunctions(arr) {
  return Array.isArray(arr) && arr.length && arr.every(i => typeof i === 'function');
}
1
2
3
4
5
6
7

我尝试给它们加上缓存,提升也不大。

而且他的代码写得比较绕,他用了一堆配置规则来处理 markdown-it (opens new window) 生成的所有 Token。这些规则写得感觉也很复杂。还用 splice 方法操作了 tokens 数组,这也是有一些性能损耗。

于是我决定还是重写吧。仓库: markdown-it-attributes (opens new window)

原作者的仓库有不少测试用例,这给我的重写工作带来了很多便利,很快这个工作就完成得差不多了。

# 测试

直接上浏览器测试,使用一个 100000 行, 350000 个字符的简单大文件测试一下。

markdown-it-attrs

markdown-it-attributes

调用时间由原来的 181ms 降低到 2.7ms!

搞个 benchmark 文件测一下更复杂的渲染情况。

node benchmark.js

simple content ---------- 100001 lines, 300000 characters
no plugin: 51ms
markdown-it-attrs: 183ms
markdown-it-attributes: 52ms
inc: 132x
complex content ---------- 290001 lines, 2668000 characters
no plugin: 393ms
markdown-it-attrs: 2321ms
markdown-it-attributes: 449ms
inc: 34.42857142857143x
compare result ----------
1
2
3
4
5
6
7
8
9
10
11
12
13

实际情况没有这么多复杂的需要解析的内容,性能表现应该更接近简单内容的情况。

# 一点经验

要写出性能还过得去的代码,一定牢记准则 “你不能让计算机变得更快,你只能让它少做一点事

  1. 使用性能评估工具测量代码
  2. 了解内置方法复杂度如 Array.splice 也可能会很消耗性能
  3. 使用正则表达式也要谨慎评估可能的复杂度,当心 ReDoS。很久以前给腾讯云提交了一个这种类型的漏洞,一个简单的请求可以让服务器持续运行很久甚至挂掉。
  4. 少一些动态操作,方便 JS 引擎优化
  5. 常见的逻辑或开销小的逻辑放前面。如 if (flag && arr.some(x => !!x)) 就比 if (arr.some(x => !!x) && flag) 好。
  6. 考虑代码是否会频繁触发垃圾回收
  7. 可以加一些适当的缓存

本文由「Yank Note - 一款面向程序员的 Markdown 笔记应用 (opens new window)」撰写