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

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

  例如在某个动作的时候需要触发三个异步方法,他们为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了,这时候就会调用回调方法。

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

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

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

javascript的闭包与一次重构的感受的更多相关文章

  1. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  2. JavaScript作用域闭包简述

    JavaScript作用域闭包简述 作用域 技术一般水平有限,有什么错的地方,望大家指正. 作用域就是变量起作用的范围.作用域包括全局作用域,函数作用域以块级作用域,ES6中的let和const可以形 ...

  3. JavaScript的闭包原理

    什么是js(JavaScript)的闭包原理,有什么作用? 一.定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分. 个人的理解是 ...

  4. Js(javaScript)的闭包原理

    问题?什么是js(javaScript)的闭包原理,有什么作用? 一.定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分.  小编 ...

  5. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  6. 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  7. javascript,jquery(闭包概念)(转)

    偶尔听人说javascript闭包,让我联想起以前学编译原理和数字逻辑里讲的闭包,以前上课讲的闭包很难懂,而且含有递归的意思在里面,现在不想再查看里面的闭包概念. 但javascript我是经常要用, ...

  8. 理解Javascript 的闭包(closure)

    要理解闭包的概念先从变量的作用域说去 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之 ...

  9. 两个示例介绍JavaScript的闭包

    JavaScript的闭包有两个用途:一个是访问函数内部的变量:另一个是让变量的值在作用域内保持不变.函数是JavaScript 中唯一有作用域的对象,因此JavaScript的闭包依赖于函数实现,下 ...

随机推荐

  1. nodejs笔记1 ----关于express不是本地命令

    1,npm install -g express安装express框架 2,npm install -g express-generator安装命令工具 3,express --help 安装完成

  2. MongoDB学习总结(二) —— 基本操作命令(增删改查)

    上一篇介绍了MongoDB在Windows平台下的安装,这一篇介绍一下MongoDB的一些基本操作命令. 下面我们直奔主题,用简单的实例依次介绍一下. > 查看所有数据库 (show dbs) ...

  3. C#中字符和字符串总结

    Char类是C#提供的字符类型,String是C#提供的字符串类型. 字符: Char类在C#中表示一个Unicode字符. Char类只定义一个Unicode字符. Char类常用的方法及说明如下: ...

  4. BZOJ 1606: [Usaco2008 Dec]Hay For Sale 购买干草(动态规划)

    裸的背包= =,没什么好说的= = CODE: #include<cstdio>#include<iostream>#include<algorithm>#incl ...

  5. 部分linux系统命令(shell 命令)和hadoop命令

    linux系统命令(shell 命令): ls :  只列出文件/目录 ls -l :  会显示文件的详情,如大小等 ls -lh :  会显示文件的详情,但大小以k或者M为单位 ls ../ :  ...

  6. 学习JVM--垃圾回收(二)GC收集器

    1. 前言 在上一篇文章中,介绍了JVM中垃圾回收的原理和算法.介绍了通过引用计数和对象可达性分析的算法来筛选出已经没有使用的对象,然后介绍了垃圾收集器中使用的三种收集算法:标记-清除.标记-整理.标 ...

  7. 在Vue中通过自定义指令获取元素

    vue.js 是数据绑定的框架,大部分情况下我们都不需要直接操作 DOM Element,但在某些时候,我们还是有获取DOM Element的需求的: 在 vue.js 中,获取某个DOM Eleme ...

  8. 用ASP.NET创建网站

    ASP.NET提供三种框架来创建web应用:WebForms,ASP.NET MVC和ASP.NET WebPages.这三种框架都是稳定成熟的,你可以用任何一种方式开发一个很棒的web应用.不管你选 ...

  9. ARZhu的数论初步

    数论 2017年3月4日02:11:35 gcd 1. 原理: gcd( a, b ) = gcd( b, a - b ) -> gcd( a, b ) = gcd( b, b % a ) 2. ...

  10. jquery.vilidate的运用

    vilidate是jquery的一个form表单验证插件非常实用 里面需要注意的就是remote的用法 /*验证*/$().ready(function() {    $(".form_al ...