最近浏览关于性能的博客比较多,
无论是拼图/懒加载等傻瓜式优化,还是逻辑上的选用设计模式等系统优化,
感觉都是挺好玩的,今天就来讲讲缓存在网站开发中的重要性。
计算斐波那契数列,也叫黄金分割数列(1,1,2,3,5,8,13...),同时也就是兔子繁衍问题,每一项等于前两项之和,
当然,数列项的其他操作就不在今天讨论的范围内了,比如 1/1=1, 1/2=0.5, 2÷3=0.666, ... 144÷233=0.618025 无限趋近于 0.618(黄金分割比)等,
计算第 n 个斐波那契数列项就需要用到下面这样的程序,
var count = 0;
function fib(n) {
count++;
if(n === 0 || n === 1) return 1;
return fib(n-2) + fib(n - 1);
}
console.log(fib(40), count); // 运行了 331160281 次
显然这样来做理论上是对的,但计算量细思极恐,
如果我们可以把计算过了的项存在缓存里,不用计算下一项时又计算一次它,是不是能优化很多呢...
var count = 0;
var fib = (function() {
var cache = [];
return function(n) {
count++;
if(cache[n] !== undefined) {
return cache[n];
}
if(n === 0 || n === 1) {
cache[n] = 1;
return cache[n];
}
var temp = arguments.callee(n - 1) + arguments.callee(n - 2);
cache[n] = temp;
return cache[n];
};
})();
console.log(fib(40), count); // 运行了 79 次
发现一般使用递归都会使运行时间增长很多,于是乎,写了下面这段代码,
将缓存模式进行了封装,于是乎,无论是简单递归还是斐波那契数列都可以很轻易的提升性能了
// 测试性能
function testFunctionTime(fn, label) {
console.time(label);
if (fn) fn();
console.timeEnd(label);
}
// 封装缓存机制
function useCache(fn) {
var cache = {};
return function(){
var key = arguments.length + Array.prototype.join.call(arguments, ",");
if (key in cache) return cache[key];
else return cache[key] = fn.apply(this, arguments);
}
}
// 斐波那契数列
function fn1() {
var count = 0;
var fib = function(n) {
count++;
if(n === 0 || n === 1) return 1;
return fib(n - 1) + fib(n - 2);
};
console.log(fib(40), count);
}
function fn2() {
var count = 0;
var fib = useCache(function(n) {
count++;
if(n === 0 || n === 1) return 1;
return fib(n - 1) + fib(n - 2);
});
console.log(fib(40), count);
}
testFunctionTime(fn1, '无缓存');
testFunctionTime(fn2, '有缓存');
嗯,效果非常 nice 哟