JS 中如何优雅的提前结束递归? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
rioshikelong121
V2EX    Javascript

JS 中如何优雅的提前结束递归?

  •  1
     
  •   rioshikelong121 2020-07-30 21:52:46 +08:00 4768 次点击
    这是一个创建于 1974 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我最近写代码的过程中,通过抛出异常来结束掉已经找到结果的递归过程。这种做法推荐么?

    这样做可以清空 Call Stack 。
    19 条回复    2020-08-07 06:55:32 +08:00
    lxk11153
        1
    lxk11153  
       2020-07-30 22:20:59 +08:00
    难道不是 return 吗?
    Mistwave
        2
    Mistwave  
       2020-07-30 22:32:49 +08:00 via iPhone
    return
    BingoXuan
        3
    BingoXuan  
       2020-07-30 22:42:19 +08:00 via Android
    为什么要抛出异常? return 就是让你回到父函数,递归回去不就是回去开头吗?

    蛇尾即是蛇头
    rioshikelong121
        4
    rioshikelong121  
    OP
       2020-07-30 22:48:15 +08:00
    分支特别深的话,return 不是只能逐层往上返回么。这一部分的性能可以忽略?

    @lxk11153 @Mistwave @BingoXuan
    ipwx
        5
    ipwx  
       2020-07-30 23:10:38 +08:00
    @rioshikelong121 可是。。。异常也是一级一级返回上去的啊。不是你自己没有写这个逻辑,它就不存在了哇。

    而且异常还有比逐级 return 更多的东西需要处理。。。
    ChanKc
        6
    ChanKc  
       2020-07-30 23:14:38 +08:00
    如果异常一下子就退掉整个栈……异常栈怎么办?你调递归的那个函数是不是也会被退出?
    rioshikelong121
        7
    rioshikelong121  
    OP
       2020-07-30 23:23:39 +08:00
    @ChanKc 比如说。我写的函数 A 里面定义并且调用了 B 。B 递归调用自身并修改 A 闭包里面的变量。等到合适的时机抛出异常。A 里面 try catch 调用 B 。 我的理解是 Call Stack 里面只会清除掉由 B 递归调用产生的上下文。不会把 A 的调用也清掉。。。
    rioshikelong121
        8
    rioshikelong121  
    OP
       2020-07-30 23:24:52 +08:00
    @ipwx 我还以为异常不需要逐层返回。而是会直接返回到捕获处或者顶层。。 如果是这样那确实没必要。
    secondwtq
        9
    secondwtq  
       2020-07-30 23:26:18 +08:00
    一般是每次递归调用后检查一下是不是有结果了,有了就顺便返回。

    楼主这异常运用灵活自如,想必以前是学 Python 的吧。
    wzzzx
        10
    wzzzx  
       2020-07-30 23:41:56 +08:00
    很明显,你写的递归有问题
    BingoXuan
        11
    BingoXuan  
       2020-07-30 23:46:30 +08:00 via Android
    @rioshikelong121
    你 debug 时候看到调用栈就是调试器一路往回捕获的结果。直接 return 就好了

    如果用 c 就可以很暴力用 goto 跳转了,但 js 和 Python 这些动态语言就不行了。
    lsvih
        12
    lsvih  
       2020-07-30 23:47:47 +08:00
    @secondwtq Python 也有异常堆栈 Traceback 的, 不背这个锅。。
    secondwtq
        13
    secondwtq  
       2020-07-31 00:33:06 +08:00
    @lsvih 我说的是 Python 的 StopIteration
    Austaras
        14
    Austaras  
       2020-07-31 00:33:48 +08:00
    等一个独立自主发明 first class continuation, 看好你哟
    ChanKc
        15
    ChanKc  
       2020-07-31 08:14:21 +08:00 via Android
    #7 那不是也要每一层去找 catch 吗
    12tall
        16
    12tall  
       2020-07-31 08:39:25 +08:00
    @rioshikelong121 可以了解一下尾递归
    lithbitren
        17
    lithbitren  
       2020-07-31 11:23:12 +08:00
    把递归用栈或队列存储存参数,然后改成迭代就可以提前结束了。
    ipwx
        18
    ipwx  
       2020-07-31 12:24:30 +08:00
    @rioshikelong121 你想一下啊,每个函数都有局部变量对吧。就算你没有 try ... catch ... ,局部变量的内存总得回收吧?调用栈的项目都得删掉吧?你 return 也不过就干了这两件事情吧?所以 throw 直接跳到顶层,只是写法上更省而已,执行过程不会省的。
    chnwillliu
        19
    chnwillliu  
       2020-08-07 06:55:32 +08:00
    难道不是依赖 js 引擎的尾调用优化? 可惜 chrome 貌似还没优化。

    http://kangax.github.io/compat-table/es6/#test-proper_tail_calls_%28tail_call_optimisation%29
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     963 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 19:08 PVG 03:08 LAX 11:08 JFK 14:08
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86