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

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

  例如在某个动作的时候需要触发三个异步方法,他们为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. C语言 一维数组叠加为二维数组样例

    这里参看memcpy的用法,将一个一维整型数组不停的叠加为二维数组 使用宏定义来控制二维数组的行列 代码如下: #include <stdio.h> #include <stdlib ...

  2. Java生成、解析二维码

    今天遇到需求,使用Java生成二维码图片,网搜之后,大神们早就做过,个人总结一下. 目标:借助Google提供的ZXing Core工具包,使用Java语言实现二维码的生成和解析. 步骤如下: 1.m ...

  3. JavaScript 深浅拷贝

    JavaScript有五种基本数据类型(Undefined, null, Boolean, String, Number),还有一种复杂的数据类型,就是对象. Undefined 其实是已声明但没有赋 ...

  4. C/C++面试之算法系列--去除数组中的重复数字

    去除数组中的重复数字 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/2008/ ...

  5. python2.7学习笔记-split用一个分隔符分割、多个分隔符分割、在有汉字存在的情况下split分割

    还是直接上程序吧,暂且就叫它为程序吧: ''' 按照多个分隔符分割,split的用法 ''' import re s='hi!chu?lan!heihei' re.split('[!?]',s) '' ...

  6. 《深入理解Java虚拟机》学习笔记之类加载

    之前在学习ASM时做了一篇笔记<Java字节码操纵框架ASM小试>,笔记里对类文件结构做了简介,这里我们来回顾一下. Class类文件结构 在Java发展之初设计者们发布规范文档时就刻意把 ...

  7. JS入门(二)

    关于运算符: js中判断运算符跟数学的运算符基本差不多,就是大于>,小于<,大于等于>=,小于等于<=,等于==,不等于!=,全等于===:可以看出来,跟我们印象中的判断运算符 ...

  8. JavaScript数据结构——栈的实现

    栈(stack)是一种运算受限的线性表.栈内的元素只允许通过列表的一端访问,这一端被称为栈顶,相对地,把另一端称为栈底.装羽毛球的盒子是现实中常见的栈例子.栈被称为一种后入先出(LIFO,last-i ...

  9. KoaHub.JS基于Node.js开发的mysql的node.js驱动程序代码

    mysql A node.js driver for mysql. It is written in JavaScript, does not require compiling, and is 10 ...

  10. Python round() 函数

    round() 方法返回浮点数x的四舍五入值. 以下是 round() 方法的语法: round( x [, n] )x为浮点数,n为保留的小数点位. 以下展示了使用 round() 方法的实例: p ...