20200325
Plan
- 你不知道的 js 中卷 -- 完结
Notes
性能测试与调优
如果单纯的使用 Date 来计算是不一定准确的,还和计时器的精度有关(这部分没有看懂是怎么计算的)
重复一个 100 次的运算,总共消耗了 137ms,那么平均用时是 1.37ms 嘛?并不完全是。如果有异常值会导致误差
可以循环运算以达到某个固定时间,而这个固定时间应该根据使用的定时器(不明白这个定时器是什么?是 setTimeout 嘛?)的精度而定。 15ms 精度的定时器需要迭代运行到 750ms 才能最小化不确定性到 1%。1ms 的定时器需要运行到 50ms 就可以达到不确定性小于 1%
不是很明白以上的计算结论?
推荐使用 Benchmark.js
测试需要考虑各种测试环境 -- 推荐 jsPerf
不要过分的纠结微性能 -- 编译器会做一定的优化
js 的引擎各有不同
针对 v8 内部细节的实现,有人总结了一下两个细节来提高代码的性能。但是不必纠结于这两条规则,万一以后不是 v8 了呢?
a) 不要把 arguments 从一个函数传到另一个函数,会降低函数实现速度 b) 把 trycatch 分离到单独的函数中。因为浏览器在优化 trycatch 时会有一些困难
尾调用优化
尾调用就是出现在另一个函数结尾处的函数调用。
function foo(x) {
return x;
}
function bar(y) {
return foo(y + 1); // 尾调用
}
function baz() {
return 1 + bar(40); // 非尾调用
}
优点: 每次调用一个新的函数都需要额外的一块预留内存来管理调用栈 -- 栈帧。以上面的例子为例:需要为每个 foo, bar, baz 保留一个栈帧。如果引擎能够识别到 foo 是尾调用,那么就可以认为 bar 基本完成了,所以可以重复利用 bar 的栈帧。这就是为什么尾调用可以提高性能
递归尾调用
function factorial(n) {
function fact(n, res) {
if (n < 2) return res;
return fact(n - 1, n * res); // 尾调用
}
return fact(n, 1); // 尾调用
}