zoukankan      html  css  js  c++  java
  • 递归那点事(下)

    上篇我们说道了一些用到递归的一些面试题,也讲了递归使用命名式函数的完善。

    不过,面试题终究是面试题,而递归在实际开发中,需要慎用。(本人不多的项目中,用到递归次数不多,仅几次是用于处理数据,该数据有类似父结构的子结构,用递归很方便)

    下篇,我们来讲讲递归的优缺点,再引申一下事件循环机制。

    递归优点:

    1.代码简洁。

    2.方便理解。

    缺点:

    1、时间和空间的消耗比较大。

    2、重复计算。

    3、调用栈溢出。

    这里提一下事件循环机制,以帮助理解递归。

    js是单线程的,这个是由其用途决定的,这是js的核心,不会改变。

    但是单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。

    所以为了完善这一点,就有了同步任务和异步任务。

    下图很好的诠释了事件循环机制,大致过程为:js从上向下读代码,主线程形成堆和栈,栈中代码执行时会调用各种外部API,将各类事件加入任务队列。在栈中的同步任务执行完后,就会从任务队列中取出这些异步任务执行。

    所以我们在使用递归时,函数不断调用,栈中任务不断增加,调用的函数因没有执行完仍在栈中没有释放,只有我们满足条件不再递归调用函数时,函数从栈顶向栈底一个个执行完毕释放掉。

    每次函数调用都要在栈中分配空间,每次函数调用向栈压入也需要一定时间,可见递归是对时间和空间的消耗比较大的。

    还有栈的容量是有限的,若是我们递归层次太多,函数执行嵌套过深,还没有能等到函数执行完毕释放,栈就满了,就会形成栈溢出。

    这里有一道面试题值得看看

    //以下代码迭代太深会造成stack溢出, 改写成不会出错的代码
    var queue = ...... //这是一个很大很大的数组
    var nextItem = function(){
        var item = queue.pop();
        if(item){
            nextItem();
        }
    }

    若是理解了事件循环机制,我们就能理解以下这个改错方案了

    var nextItem = function(){
        var item = queue.pop();
        if(item) {
            setTimeout(function(){
            nextItem()
        },0)
        }
    }

    即,使用了延时定时器,将本在同步任务的函数调用,变到了异步任务——

    1.在第一层nextItem函数执行时,item若存在,开启定时器,第二层nextItem函数的调用放到了任务队列中,并不执行。

    2.然后第一层nextItem函数执行完毕,在栈中释放。

    3.栈空后,取任务队列中的第二层nextItem函数执行。

    如此循环,像是递归,但是却非递归,我们会确保栈空后才去执行任务队列函数,这样就不会造成栈溢出了。

    参考:

    阮一峰 再谈Event Loop http://www.ruanyifeng.com/blog/2014/10/event-loop.html

    递归优缺点 https://blog.csdn.net/haovin/article/details/97033783

    转载请私聊,引用请注明出处,欢迎交流评论,但请不要发动白起大招,谢谢!
  • 相关阅读:
    Jquery 改变样式
    2017年04月06日 开启博客之路
    SVN-简要说明
    wp8 入门到精通 高仿微信发信息 键盘不消失
    wp8 入门到精通 仿QQPivot 提示数量
    wp8 入门到精通 虚拟标示符 设备ID
    wp8 入门到精通 测量代码执行时间
    wp8 入门到精通 聊天控件
    wp8 入门到精通 抓包
    wp8 入门到精通 LINQ to SQL
  • 原文地址:https://www.cnblogs.com/nys013/p/13583652.html
Copyright © 2011-2022 走看看