js递归优化
递归优化
递归在我们平时撸码中会经常用到,不过可能很多人不知道递归的弊端,就是会导致调用栈越来越深。如果没有节制的使用递归可能会导致调用栈溢出。
- 那什么是递归呢?
递归调用是一种特殊的嵌套调用,是某个函数调用自己或者是调用其他函数后再次调用自己的,只要函数之间互相调用能产生循环的则一定是递归调用,递归调用一种解决方案,一种是逻辑思想,将一个大工作分为逐渐减小的小工作,比如说一个和尚要搬50块石头,他想,只要先搬走49块,那剩下的一块就能搬完了,然后考虑那49块,只要先搬走48块,那剩下的一块就能搬完了,递归是一种思想,只不过在程序中,就是依靠函数嵌套这个特性来实现了。 - 那什么又是调用栈呢?
下面的是我写的一个简单的递归调用,通过断点我们可以看到每执行一个test函数,调用栈就会多一个test函数。
当我们执行到i=0的时候,这个时候调用栈是最深的有11个test函数,之后又会逐个移除test函数,可以看图二的动图,可以看出调用栈是先进后出的
function test (i) {
if (i < 0) return
test(--i)
}
// 这个会调用自身11次
test(10)
图1:

图2:

那怎么对递归进行优化呢,既能起到递归的作用又不会加深调用栈
这里会用到while循环的思想,调用栈之所以会加深主要是因为方法内调用方法,必须等待方法执行完成这个任务才算是真正的结束,就像A同学有个任务1,这个任务是让B同学完成任务2,在B同学没有完成之前,A同学一直处理工作状态。
那while循环是什么原理呢,可以理解为将有调用关系的方法平铺为同一级别。这需要引入额外的方法来做调度,本来test方法需要调用自己10次的,现在用方法b通过标记的方法来决定是否需要调用test方法
- 下面的的例子就是实现递归优化的实现方法(这里复制于阮一峰的es6教程)
- 这是一个很巧妙的方法,我说下它的实现步骤:
- 利用闭包将f方法保留(这里的f方法就是我们需要递归调用的方法)
- 创建value、active、accumulated三个变量,并利用了闭包原理避免被垃圾回收
- accumulated是保存每次f方法调用后需要传入f的新的形参,active是标记f方法是否执行到了最后一次循环,value是记录需要返回的值
- 下面的因为tco会return一个新的函数accumulator,所以sum=accumulator,然后再accumulator内只要accumulated长度不为0,while就会一直执行,每次执行sum方法就会accumulated.push(arguments)方法,这样accumulated长度就不会为0。所以只要f.apply(this, accumulated.shift())执行的时候一旦不调用sum(x + 1, y - 1)方法,accumulated就不会有push操作,这时while就会停止。然后就是active,我们看到if (!active) {...}这个操作,这里保证了只有第一次调用accumulator方法时会进入while循环,剩下的只是起到accumulated.push(arguments)的作用。直到while循环停止,return出来的就是经过n次调用f方法后返回的值了。
- 这样就可以把一个递归调用转换为while循环实现了
function tco(f) {
var value;
var active = false;
var accumulated = [];
return function accumulator() {
// 这里accumulated将形参入栈
accumulated.push(arguments);
// 这里保证只有第一次调用才会进入
if (!active) {
active = true;
while (accumulated.length) {
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
}
var sum = tco(function(x, y) {
if (y > 0) {
return sum(x + 1, y - 1)
}
else {
return x
}
});
sum(1, 100000)
这里可能会有点难理解,可以多试几次,打断点看看控制台的调用栈。相信还是可以看出其中的原理的
js递归优化的更多相关文章
- 应用r.js来优化你的前端
r.js是requireJS的优化(Optimizer)工具,可以实现前端文件的压缩与合并,在requireJS异步按需加载的基础上进一步提供前端优化,减小前端文件大小.减少对服务器的文件请求.要使用 ...
- js性能优化-事件委托
js性能优化-事件委托 考虑一个列表,在li的数量非常少的时候,为每一个li添加事件侦听当然不会存在太多性能方面的问题,但是当列表非常的长,长到上百上千甚至上万的时候(当然只是一个解释,实际工作中很少 ...
- js递归遍历多维数组并在修改数组的key后返回新的多维数组
我司最近正在用VUE做一个基于用户权限显示不同左侧菜单的后台管理系统,接口会根据用户的权限不同返回不同的菜单名称.URL等,前端要将这些菜单名称及URL动态添加到系统的左侧,这里就用到了vue-rou ...
- js 性能优化利器:prepack
1. js 性能优化 js 本身是没有像 python 一样的预编译功能,更没有像 java 一样的编译功能,所以,这里所说的 js 代码预编译 只是通过工具实现的类似功能而已. 这就要提到 prep ...
- 【Vue.js实战案例】- Vue.js递归组件实现组织架构树和选人功能
大家好!先上图看看本次案例的整体效果. 浪奔,浪流,万里涛涛江水永不休.如果在jq时代来实这个功能简直有些噩梦了,但是自从前端思想发展到现在的以MVVM为主流的大背景下,来实现一个这样繁杂的功能简直不 ...
- js 递归调用
js递归调用 function fact(num) { ) { ; } else { ); } } 以下代码可导致出错: var anotherFact = fact; fact = null; al ...
- 关于js回调方法 js递归时使用方法
js中递归调用本身可以这样: function a1(n){ a1(n)}但是如果需要在参数n进行自增的情况下判断会出错: function a1(n){ if(n>10) return 'aa ...
- js 性能优化 篇一
JS性能优化 摘自:http://www.china125.com/design/js/3631.htm 首先,由于JS是一种解释型语言,执行速度要比编译型语言慢得多.(注:,Chrome是第一款内 ...
- js性能优化文章集锦
总结的js性能优化方面的小知识http://www.it165.net/pro/html/201503/35336.html 如何优化你的JS代码http://www.php100.com/html/ ...
随机推荐
- OV5640摄像头配置一些值得注意的关键点(三)
一.字节标志的注意点 由于摄像头的输出是RGB56格式,所以需要将两帧的数据进行拼接,之后送到上位机进行显示. reg byte_flag; always@(posedge cmos_pclk_i) ...
- C/c.pp:贪心,二分答案
说是贪心有点牵强. 其次,答案满足单调性,如果在k次操作能完成那么在k+1次操作内也能完成. 因为大不了你就把多的一次对方操作再进行一次就好了. 怎么操作呢? 我们从头扫这个序列,遇到每一个不匹配位置 ...
- docker安装制定版本-centos7
# 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加Docker软件包源 yum-config-manage ...
- js+css3实现多行图片点击(自动)左右无缝轮播特效
/*效果图*/ HTML: <div class="scroll"> <div class="picbox"> ...
- python学习之【第十七篇】:Python中的面向对象(类和对象)
1.什么是类和类的对象? 类是一种数据结构,我们可以用它来定义对象,后者把数据值和行为特性融合在一起,类是现实世界的抽象的实体以编程形式出现.实例是这些对象的具体化.类是用来描述一类事物,类的对象指的 ...
- phpstorm设置内存限制的方法
phpstorm设置内存限制的方法有时候用phpstorm写代码 1个文件代码多的话会很卡 那就要修改内存限制 E:\Program Files (x86)\JetBrains\PhpStorm 20 ...
- 大宇java面试系列(三):Redis常见面试题
1. Redis 是什么?都有哪些使用场景? 我们先来理解经典的CAP理论: 一致性:是指从数据层面来看的一致性. 可用性:是指从系统层面的可用性. 容错性:是指从网络层面的的容错性. 数据库逐渐从关 ...
- PHP 性能优化 - php.ini 配置
内存 默认设置 memory_limit = 128M 单个进程可使用的内存最大值,这个值的设定可以从以下几点考虑: 应用的类型.如果是内存集中型应用,可增加该值: 单个 PHP 进程平均消耗的内存, ...
- 关于laravel框架Model返回的值为stdClass对象转换两种方法
一般情况下laravel模型层查询出来的数据是stdClass对象,无法直接当做数组进行视图展示,所以需要转换为数组格式. Model中查到的数据为 $data ,对它进行转化,转化为数组. 第一 ...
- 在VMware15.5中安装CentOS7_7_64bit
一.创建虚拟机 在我的另一个随笔里有. 地址为:https://www.cnblogs.com/qi-yuan/p/11692092.html 只是在虚拟机安装操作系统时候选择 Linux 而不是 W ...