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

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

  例如在某个动作的时候需要触发三个异步方法,他们为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. JavaScript处理json格式数据

    JSON即JavaScript对象标记,是一种轻量级的数据交换格式,非常适用于服务器与JavaScript的交互.JSON是基于纯文本的数据格式. JSON是JavaScript的原生格式,可以使用J ...

  2. html5_canvas初学

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. (@WhiteTaken)设计模式学习——原型模式

    有这样一个需求,两个对象,只是名称以及其他几个属性不一样,而其他的大部分的属性都是相同的. 这时候我们可以用到原型模式,也就是克隆模式. 原型模式:原型模式是一个对象创建型模式,通过克隆原对象,可以使 ...

  4. js设置、获取、清除cookie

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  5. Hadoop基本开发环境搭建(原创,已实践)

    软件包: hadoop-2.7.2.tar.gz hadoop-eclipse-plugin-2.7.2.jar hadoop-common-2.7.1-bin.zip eclipse  jdk1.8 ...

  6. Java Web(十) JDBC的增删改查,C3P0等连接池,dbutils框架的使用

    前面做了一个非常垃圾的小demo,真的无法直面它,菜的抠脚啊,真的菜,好好努力把.菜鸡. --WH 一.JDBC是什么? Java Data Base Connectivity,java数据库连接,在 ...

  7. JS中的作用域链

    在js中数据的声明方式有两种: 1.用var声明,例如:var num = 10: 2.直接声明,例如:num = 10: 两种声明方式在某些情况下是有区别的: var data = 10; func ...

  8. Number()、parseInt()、parseFloat()的区别

    最近在一个项目中遇到:需要在前台页面用javascript去处理很数值的计算. 各种用法都有,为了统一且保证处理方式正确,特地总结了一下相关的数值转换的用法: 作用: Number():可以用于任何数 ...

  9. ERP实施员的保密要求

    一.公司机密文件范围 1    公司级计算机密码 2    公司级程序软件 3    与客户联系的各种远程联系用户名,密码 4    公司发展计划.规划 5    公司客户资料.财务报表.人事薪资.报 ...

  10. .NET中的repeater简介及分页效果

    Repeater控件是一个数据绑定容器控件,它能够生成各个项的列表,并可以使用模板定义网页上各个项的布局.当该页运行时,该控件为数据源中的每个项重复此布局.  配合模板使用repeater控件 若要使 ...