javascript的闭包与一次重构的感受

 

  有没有这么一个场景,你的一个动作需要在所有异步方法执行完毕后,再进行操作?然而你对异步方法何时执行完毕感到困扰,只能在每个方法中写回调,在回调中重复劳动?

  偶然的,想起了之前经理讲过的闭包的概念,偶然的,觉得可以应用到代码中。

  例如在某个动作的时候需要触发三个异步方法,他们为a(),b(),c()。我们在d()方法中执行a,b,c。然后在三个方法执行后需要抛出一个动作,然而我们怎么知道这三个异步方法什么时候执行完呢?并且准确的在执行完的最后那个方法后抛出这个动作呢?

  //异步a
    function a(cb){
        .....
     if(cb)cb(); } //异步b function b(cb){ .....
     if(cb)cb(); } //异步c function c(cb){ .....
    if(cb)cb(); } //动作 function action(){ ... } //调用者 function main(){ a(); b(); c(); action(); }

  原本我是用一个全局变量count记录执行次数,在每个方法的回调中将执行次数减去。当有一个回调方法内的count被减为0的时候,就证明方法都执行完毕了。

    var count=3;
    //异步a
    function a(){
        .....
        if(--count<=0){
            action();
        }
    }
    //异步b
    function b(){
        .....
        if(--count<=0){
            action();
        }
    }
    //异步c
    function c(){
        .....
        if(--count<=0){
            action();
        }
    }
    //调用者
    function main(){
        a();
        b();
        c();
        //action();
    }

  是的,这个方法是能实现的,但是这个方法有点弊端,首先count是个固定值,你必须事先知道有多少个方法要执行,就是要自己数,如果新加了方法,那还要重新改变count的值,很明显这和我们的'开放-关闭'原则是背道而驰的。其次每个方法都要写一串相同的代码,复用性太低,重复性代码太多。最后,每个方法都要访问全局变量,这增加了全局资源,用我们经理说过的话,就是因为方法内的逻辑污染了到外部或全局代码。

  明白了这样写的弊端,自然是要改了。  

  《代码大全》中对'表查询法'有着很高的评价,即简洁了代码,又增加了可读性,在一些场景中甚至是提高代码性能的利器,我们何不利用?

initFun:function(){    //初始化           
                var funArr = [a, b, c];                            
                funArr.forEach(function (item) {
                    item();
                })
            }          

  好了,接下来如何用闭包实现准确在三个方法执行后调用回调?

  在这之前,我们先看看闭包的特性:访问外部变量,保持外部变量。

  访问外部变量就是能在方法内访问外部变量,参数,局部变量或函数。保持外部变量是指把访问的外部变量拘留在这个方法的上下文中,每次调用方法都会带着这个上下文。简单来说就是把我们访问的这个外部变量存储在了这个方法的内存中,类似自带一个全局变量一样。

  那么我们该如何应用到代码中呢?

    //异步a
    function a(cb){
        .....
    if(cb)cb(); } //异步b function b(cb){ .....
    if(cb)cb(); } //异步c function c(){ .....
     if(cb)cb(); }
  ...... //闭包调用 function closureFun(closureCount, closureCb) {var count = closureCount; var callback = closureCb; return function () { if (!--count) { callback(); } } }, //初始化 function initFun(){
     var funArr = [a, b, c]; //执行完所有异步方法后的回调方法 var callBack = function () { console.log('i am callback'); } //注册闭包代码 var testClosureFun = me.methods.closureFun(funArr.length, callBack); funArr.forEach(function (item) { item(testClosureFun); }) },

  初始化方法中参照表查询法,将方法暂留在一个数组中,写好回调方法,并将其注册到闭包方法。funArr.length是这个闭包方法访问的外部变量,是闭包内部判断后最终将运行的次数,每次运行完一个方法,数量减一,当所有方法执行完毕,count也就为0了,这时候就会调用回调方法。

  这段代码没有污染到全局,方法的数量也自动计算,每个方法中抽离了重复代码,也算是优化了点吧。

  虽然这不一定是最好的选择,但能在偶然间把自己学到的知识应用到实际中,成就感自然也是满满的。

  当然这优化手段有什么缺陷或不足,望能指出,如果有更好的重构方案,有人知道并能指点一二,那也是鄙人的荣幸了。

posted @ 2017-03-31 13:48  云中仙  阅读(307)  评论(0编辑  收藏  举报