尾调用优化
什么是尾调用优化
函数的调用会在内存中形成一个调用记录,被称为调用帧,调用帧会保留调用位置和内部变量等信息,一个个调用帧形成了调用栈。
而尾部调用优化,意思是:如果一个函数的结尾调用了一个函数,且这个函数不需要依赖当前函数的调用帧,那么就会只保留尾部调用的这个函数调用帧,从而节省内存。
es6要求引擎实现尾部调用优化(TCO),因为如果没有TCO会导致一些JavaScript算法因为害怕调用栈限制而降低了通过递归实现的效率。
由于缺失TCO确实会导致一些程序无法实现,所以它变成了一个重要的语言特性而不是隐藏的实现细节。
es6确保了JavaScript开发者从现在开始可以在所有符合es6+的浏览器中依赖这个优化,这对JavaScript性能来说是一个胜利。
代码示例
function foo(x) {
return x;
}
function bar(y) {
return foo(y + 1); // 尾调用
}
function baz() {
return 1 + bar(40); // 非尾调用,依赖了1
}
baz(); // 42
比较常见的还有递归:
function factorial(n) {
if (n < 2) return 1;
return n * factorial(n - 1);
}
factorial(5); // 120
//尾调用优化
function factorial(n) {
function fact(n, res) {
if (n < 2) return res;
return fact(n - 1, n * res);
}
return fact(n, 1);
}
factorial(5); // 120
需要注意:TCO只用于有实际尾调用的情况,如果你书写了一个没有尾调用的递归函数,那么性能还是会和以前一样,引擎对栈和帧的分配是有上限的,比如溢出报错,所以,如果你需要写一个递归,可以使用尾调用的方式,但是需要认真注意实现的细节。
TCO的存在对递归算法来说,引擎不再需要限制栈深度了。
分类:
你不知道的JavaScript
标签:
尾调用优化TCO
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据