小练习—FuncDelayer—JS函数延迟器

自从看了关于Jquery的deferred对象的一些文章后,森森的感觉到灰常赏心悦目。

但是假如我们平时的工作中,遇到一个项目,不允许我们使用一些长得比较【胖】库,而我们又想用类似deferred对象的功能呢...

又或者说,你觉得deferred对象的使用方式不是很顺手,和你的编程思维习惯有点冲突,导致经常有一种不自在的感觉呢...

然后,今日在公司的基类库中,发现了功能类似的简化类。

它的特点就是精简轻便,又能实现函数延迟执行,而且用法跟我们平时正常的思维很类似。

在花了一段时间窥探其源码后,很是喜欢,也感到非常的实用。

于是乎,昨天在家里闲来无事,自己凭着仅余的3成实现思路印象,自己琢磨出一个函数延迟器工具类。

也算是一个小小的练习吧,哈哈~~

首先上代码,内附丰富注释,相信只要会汉语都能看懂了吧~


(function(window){
/* === Class DelayedFunc begin === */
/*
用 DelayedFunc 类创建的对象包含5属性
func 【function】 需要触发的函数实体
allowCount 【int】 已经成功触发的条件数
conditionCount 【int】 需要触发的条件数
allowFlag 【bool】 该函数的所有触发条件都已经触发了,其值就为true,否则其值就为false
conditionStatusList 【Obj】 此对象包含的子属性的数目将等于conditionCount的值,这n个属性的属性名和触发条件名相同
*/
var DelayedFunc = function(func, conditionCount){
var _this = this;
_this.func = func;
_this.conditionCount = conditionCount;
_this.allowCount = 0;
_this.allowFlag = false;
_this.conditionStatusList = {};
};

DelayedFunc.prototype.checkStatus = function(){
var _this = this;

if(_this.allowFlag){
return true;
}

if(_this.allowCount == _this.conditionCount){
_this.allowFlag = true;
return true;
}

return false;
}

/* === Class FuncDepot begin === */
var FuncDepot = function(){
var _this = this;
//初始化触发条件列表
_this.conditionList = {};
//初始化函数库存列表
_this.stockList = {};
};

/*
* 参数说明:
* condition 【Array】 触发条件list
* func 【function】 满足触发条件时,需要触发的函数
* */
FuncDepot.prototype.stockPush = function(condition, func){
var _this = this,
condition_length = condition.length,
curStock = null,
stockName = condition.join(‘_‘);

if(typeof _this.stockList[stockName] == "undefined"){

/*
如果指定的库存函数对象不存在,就在函数库存列表中插入一个新的库存函数对象
同时定义一个局部变量,缓存该对象(当前库存函数对象),以便后面的代码快速引用它
*/
curStock = _this.stockList[stockName] = new DelayedFunc(func, condition_length);

}else{

//如果指定的库存函数对象已经存在,直接引用它
curStock = _this.stockList[stockName];
curStock.func = func;

}

if(curStock.allowFlag){

//当前库存函数对象 的函数触发标记为true时,直接触发函数
curStock.func.call();

}else{

//遍历触发条件list
for(var i = 0; i < condition_length; i++){

var curCondition = condition[i];
//如果触发条件列表(conditionList)中,对应的触发条件的值为true(该条件已经被触发)
if(_this.conditionList[curCondition]){

//为 当前库存函数对象 插入条件属性,并设置其值为true
curStock.conditionStatusList[curCondition] = true;
curStock.allowCount++;

}else{

//否则,为 当前库存函数对象 插入条件属性,并设置其值为false
curStock.conditionStatusList[curCondition] = false;

}

}

if(curStock.checkStatus()){

//该函数的所有触发条件都已经触发了
curStock.func.call();

}

}
};

/*
* 参数说明:
* condition 【Array】 触发条件list
* */
FuncDepot.prototype.stockPop = function(condition) {
var _this = this, condition_length = condition.length, stockItem;

//遍历函数库存列表
for(stockItem in _this.stockList){

for(var i = 0; i < condition_length; i++){

var curCondition = condition[i];
//进行库存函数名称匹配,如果库存函数名含有与某个触发条件相同的字符,说明该库存函数含有此触发条件
if(stockItem.indexOf(curCondition) != -1){

var curStock = _this.stockList[stockItem];

if(curStock.allowFlag){

//如果该函数的所有触发条件都已经满足,直接触发该函数
curStock.func.call();
//并跳出名称匹配这一层循环,继续遍历函数库存列表,因为没有必要继续做条件匹配了
break;

}else{

//该函数并未所有触发条件满足,且当前正在触发的条件正是未被触发的
if(!curStock.conditionStatusList[curCondition]){

//将该函数的对应触发条件设为true(已触发),已触发条件数+1
curStock.conditionStatusList[curCondition] = true;
curStock.allowCount++;

}

//触发条件相关属性变更完后,判断已触发条件数是否与需要触发的条件数相同,如果相同,则所有触发条件都已触发
if(curStock.checkStatus()){

//所有触发条件都已触发,allowFlag属性设为true,并直接执行该函数
curStock.func.call();
//并跳出名称匹配这一层循环,继续遍历函数库存列表,因为没有必要继续做条件匹配了
break;

}

}

}

}

}
};

/* === Class FuncDelayer begin === */
var FuncDelayer = function(){
var _this = this;
_this.funcDepot = new FuncDepot();
};

/*
* 参数说明:
* condition 【String】
* 触发条件list的表达字符串,各个条件由英文逗号","分隔开
* 字符串中的所有空格符都会被过滤掉,建议仅用英文和数字组织触发条件名
* func 【function】 满足触发条件时,需要触发的函数
* */
FuncDelayer.prototype.push = function(condition, func){
var _this = this,
condition = condition.replace(/ /g, ‘‘).split(‘,‘);

for(var i = 0, j = condition.length; i < j; i++){

var curCondition = condition[i];
//如果该触发条件并未加入触发条件列表中
if(!_this.funcDepot.conditionList[curCondition]){

//将该触发条件插入到触发条件列表,触发条件的值为false(未触发)
_this.funcDepot.conditionList[curCondition] = false;

}

}

_this.funcDepot.stockPush(condition, func);
};

/*
* 参数说明:
* condition 【String】
* 触发条件list的表达字符串,各个条件由英文逗号","分隔开
* 字符串中的所有空格符都会被过滤掉,建议仅用英文和数字组织触发条件名
* */
FuncDelayer.prototype.pop = function(condition){
var _this = this,
condition = condition.replace(/ /g, ‘‘).split(‘,‘);

for(var i = 0, j = condition.length; i < j; i++){

var curCondition = condition[i];
//如果触发条件列表中包含此触发条件,就会直接将其设为true
//如果触发条件列表中不包含此触发条件,则会将该触发条件插入到触发条件列表,触发条件的值为true(已触发)
_this.funcDepot.conditionList[curCondition] = true;

}

_this.funcDepot.stockPop(condition);
};

window.FuncDelayer = FuncDelayer;
})(window);

接下来说说用法:

首先当然是创建一个funcDelayer对象,这个对象提供了两个方法,push
和 pop,是不是想到数组了?

矮油~人家压根就是抄数组的方法命名嘛,嘎嘎嘎嘎~~

不过,名字虽然一样,用法还是有区别D~

push:用来给函数仓库装进一个函数,并指定该函数的触发条件

pop:触发指定的条件

funcDelayer对象有一个很美的地方,就是,你可以先往函数仓库装进函数,再触发该函数指定的条件,从而达到触发该函数的效果。

也可以先触发某个条件,然后再给函数仓库装进一个函数,并指定该函数的触发条件是先前已经触发了的条件,这样函数在装进仓库后就马上被调用了。

有了这一个特性,此对象就能在异步请求中很好的发挥了。

下面上几个实际应用例子:


//先创建一个funDelayer对象...
var funcDelayer = new FuncDelayer();

//先来个最简单的~
$.ajax({
  ...//省略N行代码,自己补吧
  success: function(data){
    funcDelayer.pop(‘getDataSuccess‘);
  }
});

funcDelayer.push(‘getDataSuccess‘, function(){
  alert(‘成功了~~‘);
});


//先创建一个funDelayer对象...
var funcDelayer = new FuncDelayer();

//反过来也行,结果都一样~
$.ajax({
  ...//这里省略N行代码,自己补吧
  success: function(data){
    funcDelayer.push(‘getDataSuccess‘, function(){
      alert(‘成功了~~‘);
    });
  }
});

funcDelayer.pop(‘getDataSuccess‘);


//先创建一个funDelayer对象...
var funcDelayer = new FuncDelayer();

//啥?上面两个例子其实和直接执行回调函数没区别?那这样呢?
$.ajax({
  ...//省略N行代码,自己补吧
  success: function(data){
    funcDelayer.pop(‘getDataSuccessA‘);
  }
});

$.ajax({
  ...//省略N行代码,自己补吧
  success: function(data){
    funcDelayer.pop(‘getDataSuccessB‘);
  }
});

funcDelayer.push(‘getDataSuccessA, getDataSuccessB‘, function(){
  alert(‘成功了~~这次可是两个异步请求都完成了才会触发哦~~‘);
});

//当然,3个甚至更多的异步请求,照样没问题


//先创建一个funDelayer对象...
var funcDelayer = new FuncDelayer();

//接下来是FunDelayer类的特性展示,下面的代码,请一句一句的,分别在控制台中执行

funcDelayer.push(‘successA‘, function(){
  alert(‘A 成功了~~‘);
});

funcDelayer.push(‘successA, successB‘, function(){
  alert(‘A and B 成功了~~‘);
});

//这句执行后,触发 A 函数
funcDelayer.pop(‘successA‘);

//这句执行后,触发 A 函数,因为 A 函数的触发条件在前面已经触发了,但弹出的信息变了,说明原来的函数被覆盖了
funcDelayer.push(‘successA‘, function(){
  alert(‘A成功了,但原函数被覆盖了~~‘);
});

//这句执行后,触发 A and B 函数
funcDelayer.pop(‘successB‘);

//再一次执行这句,触发 A 函数,同时也触发 A and B 函数,如果条件 A 和 B 前面都已经触发,那么后面只要触发其中任何一个条件,都能触发 A and B 函数
funcDelayer.pop(‘successA‘);

实例就到这里,上面最后一个实例,展示的FunDelayer类特性,可能有些人会觉得不爽,不完美。

这个问题嘛,我也纠结过,但没办法,小生的水平也就这样(能写成现在这模样,还是借用了公司老鸟的设计思路的前提之下呀...)

而且为了确保这个类的轻,适当的留一点缺陷,在使用的时候注意点,也未尝不可。

最后,如果有神马好的见解,或者发现代码中有什么问题或不足,欢迎留言,好让我改进。

小生在此先谢过了~~

时间: 2024-08-03 13:32:13

小练习—FuncDelayer—JS函数延迟器的相关文章

【JS小技巧】JavaScript 函数用作对象的隐藏问题

用户反馈 @消失的键盘 在论坛反馈了一个问题,在 AppBoxMvc 中的 Title 模型中,如果将 Name 属性改名为小写的 name 属性,就会报错: 因为这是一个 ASP.NET MVC 的项目,而这个属性是通过 TextBoxFor 渲染到页面上的,因此 name 会生成为 DOM 节点的 id 属性: F.SimpleForm() .ID("SimpleForm1") .ShowBorder(false) .ShowHeader(false) .BodyPadding(1

JavaScript入门:006—JS函数的定义

JS函数的声明.声明函数的格式如下: function 函数名(参数列表){ //函数语句: return 返回值; } 来看具体的函数声明.1.普通函数 <script type="text/javascript"> function ShowHint() { alert("普通函数"); } </script> 2.带参数的函数 <script type="text/javascript"> functio

VC与JavaScript交互(二) ———— 调用JS函数

这一章,我们来动手实践VC调用JS函数. 我们动手写一个HTML,其中包含这样一段JS代码: [html] view plaincopy <script type="text/javascript"> function Add(value1, value2) { return value1 + value2; } </script> 然后我们用WebBrowser加载这个HTML后,在VC中这样来调用这个函数名为Add的JS函数: [cpp] view plai

js函数收集

常见js函数收集: 转自:http://www.qdfuns.com/notes/36030/2eb2d45cccd4e62020b0a6f0586390af.html //运动框架 function animate(obj,targetJson,time,callback){ if(window.navigator.userAgent.indexOf("MSIE") != -1){ var interval = 50; }else{ var interval = 10; } //得到

js函数大全

js函数集·字符串(String) 1.声明 var myString = new String("Every good boy does fine."); var myString = "Every good boy does fine."; 2.字符串连接 var myString = "Every " + "good boy " + "does fine."; var myString = "

小tips:JS之浅拷贝与深拷贝

浅拷贝: function extendCopy(p) { var c = {}; for (var i in p) { c[i] = p[i]; } return c; } 深拷贝: function deepCopy(p, c) { var c = c || {}; for (var i in p) { if (typeof p[i] === 'object') { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c

JS函数-我调用自己试试看

前言 最近在读<JavaScript语言精粹>,对递归函数有了进一步的认识,希望总结下来: 递归是一种强大的编程技术,他把一个问题分解为一组相似的子问题,每一问题都用一个寻常解去解决.递归函数就是会直接或者间接调用自身的一种函数,一般来说,一个递归函数调用自身去解决它的子问题. "汉诺塔"经典递归问题 "汉诺塔"是印度的一个古老传说,也是程序设计中的经典的递归问题,是一个著名的益智游戏: 题目如下: 塔上有三根柱子和一套直径各不相同的空心圆盘,开始时源柱

关于js函数,方法,对象实例的一些说明

朋友们大家好,好久没有更新文章了,最近正好有空就想着写点什么吧,加上这段时间总是能听到一些朋友们问关于js函数,方法,对象实例到底有什么区别这个问题,所以今天就献丑来简单说明一些吧! 其实这些主要都是一些概念上的东西,在这里还是推荐大家多看看诸如<JavaSript权威指南>,<JavaScript高级编程>之类的书籍,当然这些概念如果用代码写出来我相信大家也都还是能够知道的,所以下面我就用文字和代码举一些简单的例子进行说明: 函数:简单的说函数就是,使用function关键字定义

通用js函数集锦&lt;来源于网络&gt; 【二】

通用js函数集锦<来源于网络> [二] 1.数组方法集2.cookie方法集3.url方法集4.正则表达式方法集5.字符串方法集6.加密方法集7.日期方法集8.浏览器检测方法集9.json方法10.extend方法11.类型判断的方法 数组方法集 Angela.array = { //# 数组方法 // index, 返回位置! 不存在则返回 -1: index: function (t, arr) { //# 返回当前值所在数组的位置 if (arr.indexOf) { return ar