21层嵌套的递归解决方案


刚才看到一篇文章《21 nested callbacks》,作者吐槽了一下当时他学编程时的一个趣事:为了写一个HTML的动画,他写了有21层嵌套的函数。由于作者主要是抒情,所以这样的英文很不好阅读。我就把他最重要的思想提取出来。

1,最初的实现,朴素的实现

其实这个小哥就是想把20个div依次展现在用户的眼前。他用了JQuery库的animate函数,这个函数接受一个回调,当动画完成时这个回调函数被执行。小哥最初的想法很朴素,那就是,当第一个div被显示出来的时候,传入回调函数来显示第二个div,代码类似于:

$(".disappear").click(function(){
  $("#div1").animate({ "opacity": "100" },
    100,
    function(){$("#div2").animate({ "opacity": "100" },
      100,
      function(){$("#div3").animate({ "opacity": "100" },
        100,
----------omit for brevity----------
          function(){$("#div20").animate({ "opacity": "100" },
            100)           
})})})})})})})})})})})})})})})})})})})})})})})})

坦白讲这个想法也还行,至少能正确实现功能,就是代码太难看了,要整整21个回调函数。通常来讲这也是最符合人类直觉的,现实中人们就是这样解决问题的。这也可能是范凯在《Ruby社区应该去Rails化了》说NodeJS的编程风格是反人类的主要原因:

node.js的Event IO编程风格在我看来是“反人类”的,极其变态的。用来写代码上规模的应用,代码的可读性和可维护性都很差。Event IO是很底层的技术,我很难理解为何不封装成coroutine来使用。node.js只适合用来开发real-time类型的应用。

如果按这样的方式来实现,确实他妈的反人类,正如这个小哥自嘲他自己是“狂有耐心”。

2,函数式的实现,递归实现

从代码中看,第一直觉可能就是相似的代码太多了。如果想要更好看的代码,必须减少重复,也就是我们常说的DRY。单从代码外观上看这个函数明显有个“展开”,如果从代码的执行上看有个“收缩”的过程。这不就是递归吗?

function hideOrShowPrev($elem, opacity){
    $elem.animate({ "opacity": opacity },
        100,
        function(){
            var $toHide = $elem.prev();
            if($toHide){
                hideOrShowPrev($toHide, opacity);
            }            
    })
}

$("#start").click(function(){
   hideOrShowPrev( $('#row20'), 100);
});

这个实现是我Copy评论中的一个哥们的。

published at March 28, 2013, 8 a.m.

Comments:

Sharing your thoughts: