技巧型设计模式是I通过一些特定技巧来解释组件的某些问题。主要包含链模式、委托模式、数据模式、数据访问对象模式、节流模式、简单模板模式、惰性模式、参与者模式、等待者模式。
链模式
在对象方法中将当前对象返回,实现了对同一个对象多个方法链式调用。简化了在对对象多个方法的多次调用时,对该对象多次引用。在jQuery的使用中,链式调用是最平不过了。
/** * 链模式 * 元素获取的模式 * @param selector 选择符 * @param context 上下文 */ var Dom = function(selector,context){ return new Dom.fn.init(selector,context) } Dom.fn = Dom.prototype = { constructor:Dom, init:function(selector,context){ //获取元素长度 this.length = 0; context = context || document; //若是ID选择符,按位非把-1转化为0,,布尔值false if (~selector.indexOf("#")) { this[0] = document.getElementById(selector.slice(1)); this.length = 1; }else{ //是元素名称 var doms = context.getElementsByTagName(selector); var i = 0; var len = doms.length; for(;i<len;i++){ this[i] = doms[i]; } this.length = len; } this.context = context; this.selector = selector; return this; } } /** * 对象拓展 */ Dom.extend = Dom.fn.extend = function(){ //从第二参数开始拓展 var i =1; var len = arguments.length; var target = arguments[0]; var j; //只传递 一个参数 if (i == len) { target = this; i--; } for(;i<len;i++){ for(j in arguments[i]){ target[j] = arguments[i][j]; } } return target } Dom.fn.extend({ //添加事件 on:(function(){ if (document.addEventListener) { return function(type,fn){ var i = this.length - 1; for(;i>=0;i--){ this[i].addEventListener(type,fn,false); } return this; } }else if(document.attachEvent){ //IE浏览器的DOM2级事件 return function(type,fn){ var i = this.length - 1 ; for(; i>=0;i--){ this[i].addEvent("on"+type,fn); } return this; } }else{ return function(type,fn){ var i = this.length - 1; for(;i>=0;i--){ this[i]['on'+type] = fn; } return this; } } })() }) Dom.extend({ //把分割线转化为驼峰形式 camelClass:function(str){ return str.replace(/\-(\w)/g,function(all,letter){ return letter.toUpperCase(); }) } }); Dom.extend({ css:function(){ var arg = arguments; var len = arg.length; if (this.length < 1) { return this; } if (len === 1) { if (typeof arg[0] ==="string") { if (this[0].currentStyle) { return this[0].currentStyle[name]; }else{ return getComputedStyle(this[0],false)[name]; } }else if(typeof arg[0] === "object"){ //设置多个样式 for(var i in arg[0]){ for(var j = this.length-1;j>=0;j--){ this[j].style[Dom.camelClass(i)] == arg[0][i]; } } } }else if(len === 2){ //两个参数设置一个参数 for(var j = this.length-1;j>=0;j--){ this[j].style[Dom.camelClass(arg[0])] = arg[1] } } return this; } }) /** * 获取、设置CSS样式,传递一个参数。如果参数是字符串就返回第一个元素的CSS样式值,如果是对象,那么就为每一个元素设置多个样式;如果传递两个参数,就为每一个元素设置样式 */ Dom.fn.extend({ attr:function(){ var arg = arguments; var len = arg.length; if (this.length < 1) { return this; } if (len === 1) { if (typeof arg[0] === "string") { return this[0].getAttribute(arg[0]); }else if(typeof arg[0] === "object"){ for(var i in arg[0]){ for(var j = this.length - 1 ;j>=0;j--){ this[j].setAttribute(i,arg[0][i]); } } } }else if(len === 2){ //两个参数就设置每个元素的单个样式 for(var j = this.length-1;j>=0;j--){ this[j].setAttribute(arg[0],arg[1]); } } return this; } }); /** * 获取元素属性 * 只传递一个参数,,如果参数是字符串就返回第一个元素属性。 * 如果参数是对象,设置每个元素多个属性值; * 传递两个参数,第一个参数为属性名,第二个参数为属性值,设置每个元素的属性 */ Dom.fn.extend({ //获取、设置元素的内容 html:function(){ var arg = arguments; var len = arg.length; //没有参数就获取第一个元素的内容 if (len === 0) { return this[0] && this[0].innerHTML; }else{ for(var i = this.length-1;i>=0;i--){ this[i].innerHTML = arg[0]; } } return this; } })
委托模式(Entrust)
多个对象接受同一个请求,把请求委托给另外一个对象统一处理请求。节省了请求的时间和流量如下:
/** * 委托模式 * 统一请求的处理 */ var Deal = { banner:function(){}, aside:function(){}, article:function(){}, memer:function(){}, message:function(){} } $.get("deal.php?",function(res){ //数据分包 for(var i in res){ Deal[i] && Deal[i](res[i]) } })
数据访问对象模式(DAO)
抽象与封装对数据源的访问和存储,DAO通过对数据源的管理方便对数据的访问和存储
/** * 本地存储类 * @param perId 本地存储数据前缀 * @param timeSign 时间戳和存储数据之间的拼接符 */ var BaseLocalStorage = function(preId,timeSign){ //定义本地存储数据库的前缀 this.preId = preId; this.timeSign = timeSign || '|-|'; } //本地存储类原型方法 BaseLocalStorage.prototype = { status :{ SUCCSS:0, //成功 FAULURE:1, //失败 OVERFLOW:2, //溢出 TIMEOUT:3 //过期 }, //保存本地数据 storage:localStorage || window.localStorage, getKey:function(key){ return this.preId+key; }, /** * 添加(修改)数据 * @param {*} key 数据字段标识 * @param {*} value 数据值 * @param {*} callback 回调函数 * @param {*} time 添加时间 */ set:function(key,value,callback,time){ //默认操作状态成功 var status = this.status.SUCCSS; var key = this.getKey(key); try { //时间参数获取时间戳 time = new Date().getTime(key) || time.getTime(); } catch (e) { //传入时间参数或者时间参数有误时,默认时间为一个月 time = new Date().getTime() + 31 * 24 * 60 * 60 * 1000; } try { //向数据库中添加数据 this.storage.setItem(key,time+this.timeSign + value); } catch (e) { //溢出失败,返回溢出状态 status = this.status.OVERFLOW; } //有回调函数就执行回调函数并且传入参数操作状态。。真实数据字段标识以及存储数据值 callback && callback.call(this,status,key,value); }, /** * 获取数据 * @param {*} key 数据字段标识 * @param {*} callback 回调函数 */ get:function(key,callback){ //默认操作状态是成功的 var sattus = this.status.SUCCSS; var key = this.getKey(key); var value = null; //拼接符的长度 var timeSignLen = this.timeSign.length; //缓存当前对象 var that = this; //时间戳和存储数据拼接的起始位置 var index; var time; var result; try { value = that.storage.getItem(key); } catch (e) { result = { status:that.status.FAULURE, value:null }; callback && callback.call(this,result.status,result.value); return result } if (value) { index = value.indexOf(that.timeSign); time = +value.slice(0,index); if (new Date(time).getTime() > new Date().getTime() || time == 0) { value = value.slice(index+timeSignLen); }else{ value = null; status = that.status.TIMEOUT; that.remove(); } }else{ //未获取数据字符串状态为失败状态 status = that.status.FAULURE; } result = { status:status, value:value }; callback && callback.call(this,result.status,result.value); return result }, /** * 删除数据 * @param {*} key 数据字段标识 * @param {*} callback 回调函数 */ remove:function(key,callback){ var status = this.status.FAULURE; var key = this.getKey(key); var value = null; try { value = this.storage.getItem(key); } catch (e) {} if (value) { try { this.storage.removeItem(key); status = this.status.SUCCSS } catch (e) {} } callback && callback.call(this,status,status>0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length)) } }
数据访问对象模式,是对数据库操作的封装。在node.js中对数据库的操作,如下实例:
/** * 本地存储类 * @param perId 本地存储数据前缀 * @param timeSign 时间戳和存储数据之间的拼接符 */ var BaseLocalStorage = function(preId,timeSign){ //定义本地存储数据库的前缀 this.preId = preId; this.timeSign = timeSign || '|-|'; } //本地存储类原型方法 BaseLocalStorage.prototype = { status :{ SUCCSS:0, //成功 FAULURE:1, //失败 OVERFLOW:2, //溢出 TIMEOUT:3 //过期 }, //保存本地数据 storage:localStorage || window.localStorage, getKey:function(key){ return this.preId+key; }, /** * 添加(修改)数据 * @param {*} key 数据字段标识 * @param {*} value 数据值 * @param {*} callback 回调函数 * @param {*} time 添加时间 */ set:function(key,value,callback,time){ //默认操作状态成功 var status = this.status.SUCCSS; var key = this.getKey(key); try { //时间参数获取时间戳 time = new Date().getTime(key) || time.getTime(); } catch (e) { //传入时间参数或者时间参数有误时,默认时间为一个月 time = new Date().getTime() + 31 * 24 * 60 * 60 * 1000; } try { //向数据库中添加数据 this.storage.setItem(key,time+this.timeSign + value); } catch (e) { //溢出失败,返回溢出状态 status = this.status.OVERFLOW; } //有回调函数就执行回调函数并且传入参数操作状态。。真实数据字段标识以及存储数据值 callback && callback.call(this,status,key,value); }, /** * 获取数据 * @param {*} key 数据字段标识 * @param {*} callback 回调函数 */ get:function(key,callback){ //默认操作状态是成功的 var sattus = this.status.SUCCSS; var key = this.getKey(key); var value = null; //拼接符的长度 var timeSignLen = this.timeSign.length; //缓存当前对象 var that = this; //时间戳和存储数据拼接的起始位置 var index; var time; var result; try { value = that.storage.getItem(key); } catch (e) { result = { status:that.status.FAULURE, value:null }; callback && callback.call(this,result.status,result.value); return result } if (value) { index = value.indexOf(that.timeSign); time = +value.slice(0,index); if (new Date(time).getTime() > new Date().getTime() || time == 0) { value = value.slice(index+timeSignLen); }else{ value = null; status = that.status.TIMEOUT; that.remove(); } }else{ //未获取数据字符串状态为失败状态 status = that.status.FAULURE; } result = { status:status, value:value }; callback && callback.call(this,result.status,result.value); return result }, /** * 删除数据 * @param {*} key 数据字段标识 * @param {*} callback 回调函数 */ remove:function(key,callback){ var status = this.status.FAULURE; var key = this.getKey(key); var value = null; try { value = this.storage.getItem(key); } catch (e) {} if (value) { try { this.storage.removeItem(key); status = this.status.SUCCSS } catch (e) {} } callback && callback.call(this,status,status>0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length)) } } /** * 在NodeJS的配置项中设置 * config.js */ module.exports = { DB:{ db:"demo", host:"localhost", port:3306 } } /** * db.js * 引用mongodb模块 */ var mongodb = require("mongedb"); var config = require("./config").DB; var d = new mongodb.Db( config.db, //数据库名 new mongodb.Server( config.host, //主机 config.port, //端口号 {auto_reconnect:true} //自动连接 ), {safe:true} ); exports.DB = function(DB){ return { /** * 插入数据 * @param data * @param success * @param fail */ insert:function(data,success,fail){ connect(col,function(col,db){ col.insert(data,function(err,docs){ if(err){ fail && fail(err); }else{ success && success(docs); } db.close(); }); }); }, /** * 删除数据 * @param data * @param success * @param faill */ remove:function(data,success,fail){ connect(col,function(col,db){ col.remove(data,function(err,len){ if(err){ fail && fail(err); }else{ success && success(len); } db.close() }) }) }, /** * 更新数据 * @param con * @param doc * @param success * @param faill */ update:function(con,doc,success,fail){ connect(col,function(col,db){ col.update(con,doc,function(err,len){ if(err){ fail && fail(err); }else{ success && success(len) } db.close(); }) }) }, /** * 查找数据 * @param con * @param success * @param fail */ find:function(con,success,fail){ connect(col,function(col,db){ col.find(con).toArray(function(err,docs){ if(err){ fail && fail(err) }else{ success && success(docs); } db.close(); }) }) } } } /** * 打开数据库,操作集合 * @param col 集合明个 * @param fn 操作方法 */ function connect(col,fn){ d.open(function(err,db){ if(err){ throw err; }else{ db.collection(col,function(err,col){ if(err){ throw err; }else{ fn && fn(col,db); } }); } }); } //test var book = DB("book"); book.insert({title:"java",type:"js"})
节流模式(Throttler)
针对重复业务逻辑进行节流控制,执行最后一次操作并且取消其他的操作,提高性能。
节流器第一件事就是清除将要执行的函数,第二就是延迟执行函数。如下:
/** * 节流模式 * 对于重复业务逻辑进行节流控制,执行最后一次操作, * 并且取消其他的操作,从而提高性能 * 如下: */ //节流器 var throttle = function(){ //获取第一个参数 var isClear = arguments[0]; var fn; if (typeof isClear === "boolean") { fn = arguments[1]; fn.__throttleID && clearTimeout(fn.__throttleID); }else{ fn = isClear; param = arguments[1]; var p = extend({ context:null, args:[], time:300, },param); arguments.callee(true,fn); fn.__throttleID = setTimeout(() => { fn.apply(p.context,p.args); }, p.time); } } /** * 创建浮层类 ,用于优化浮层 * 鼠标滑过时,显示对应的二维码图片 */ var Layer = function(id){ this.container = $(id); this.layer = $tag("div",container)[0]; this.lis = $tag("li",this.container); this.imgs = $tag("img",this.container); //绑定事件 this.bindEvent(); } layer.prototype = { //交互事件 bindEvent:function(){ //缓存当前对象 var that = this; function hiddeLayer(){ that.layer.className = ""; } function showLayer(){ that.layer.className = "show"; } that.on(that.container,'mouseenter',function(){ throttle(true,hiddeLayer); throttle(showLayer); }).on(that.container,"mouseleave",function(){ //延迟浮层隐藏 throttle(hiddeLayer); //清除显示浮层方法计时器 throttle(true,showLayer); }); //绑定icon事件 for(var i=0;i<that.lis.length;i++){ that.lis[i].index = i; that.on(that.lis[i],"mouseenter",function(){ var index = this.index; for(var i = 0;i<that.imgs.length;i++){ that.imgs[i].className = ""; } that.imgs[index].className = "show"; that.layer.style.left = -22 + 60*index+"px"; }) } }, //事件绑定的方法 on:function(ele,type,fn){ ele.addEventListener ? ele.addEventListener(type,fn,false) : ele.attachEvent("on"+type,fn); return this; } } /** * 节流延迟图片加载 * @param id 加载图片的容器 */ function Layerload(id){ this.container = document.getElementById(id); this.imgs = this.getImgs(); this.init(); } Layerload.prototype = { init:function(){ this.update(); this.bindEvent(); }, //获取加载图片 getImgs:function(){ var arr = []; var imgs = this.container.getElementsByTagName("img"); for(var i = 0,len=imgs.length;i<len;i++){ arr.push(imgs[i]) } return arr; }, //加载图片 update:function(){ if (!this.imgs.length) { return } var len = this.imgs.length; for(--i;i>=0;i--){ //图片在可视范围内 if (this.show(i)) { this.imgs[i].src = this.imgs[i].getAttribute('data-src'); //清除缓存中的图片 this.imgs.splice(i,1); } } }, show:function(i){ var img = this.imgs[i]; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; var scrollBottom = scrollTop+document.documentElement.clientHeight; var imgTop = this.pageY(img); var imgBottom = imgTop + img.offsetHeight; if (imgBottom>scrollTop && imgBottom<scrollBottom || (imgTop > scrollTop && imgTop<scrollBottom)) { return true; } return false; }, pageY:function(element){ //存在父元素 if (element.offsetParent) { return element.offsetTop + this.pageY(element.offsetParent); }else{ return element.offsetTop } }, on:function(element,type,fn){ if (element.addEventListener) { addEventListener(type,fn,false); }else{ element.attachEvent("on"+type,fn,false); } }, bindEvent:function(){ var that =this; this.on(widnow,"resize",function(){ throttle(that.update,{context:that}); }); this.on(widnow,'scroll',function(){ throttle(that.update,{context:that}); }) } } /** * 使用节流模式打包来优化请求次数 */ var LogPack = function(){ var data = [],//请求缓存数组 MaxNum = 10, //缓存最大值 itemSplitStr = '|',//统计参数间隔符号 keyValueSplitStr = "*" ,//统计参数键值对间隔 img = new Image(); //请求触发器, function sendLog(){ //请求参数 var logStr = ''; fireData = data.splice(0,MaxNum); for(var i =0,len = fireData.length;i<len;i++){ logStr += 'log'+i+"="; for(var j in fireData[i]){ logStr += j + keyValueSplitStr + fireData[i][j]; logStr += itemSplitStr; } logStr = logStr.replace(/\|$/,'') + "&"; } logStr += "logLength="+len; img.src = "d.gif?"+logStr; } //统计的方法 return function(param){ //没有参数就发送统计 if (!param) { sendLog(); return; } //添加统计项 data.push(param); //统计项大于请求缓存最大值就发送统计请求包 data.length>=MaxNum && sendLog(); } } //测试 btn.onclick = function(){ LogPack({ btnId:this.id, context:this.innerHTML, type:'click' }); }
简单模板模式
通过格式化字符串拼接出视图,避免创建视图时的大量节点操作。
/** *简单模板模式,就是字符串拼接 网站活动主题模板实例 */ //命名空间 var D = D || {}; //主体展示区容器 var root = document.getElementById("container"); D.templateString = function(str,data){ return str.replace(/\{#(\w+)#\}/g,function(match,key){return typeof data[key] === undefined ? "" : data[key]}); } //模板生成器 D.View = function(name){ var v = { code:` <pre><code>{#code#}</code></pre>`, img:`<img src="{#src#}" alt="{#alt#}" title="{#title#}"/>`, part:`<div id="{#id#}" class="{#class#}">{#part#}</div>`, theme:[ `<div> <h1>{#title#}</h1> {#content#} </div>` ].join('') } if(Object.prototype.toString.call(name) === "[Object Array]"){ var tpl = ""; for(var i=0,len=name.length;i<len;i++){ tpl += arguments.callee(name[i]); } return tpl; }else{ return v[name] ? v[name] : ('<'+name+'>{#'+name+'#></'+name+'>'); } } //创建视图的方法集合 D.strategy = { "listPart":function(data){ var s = document.createElement("div"), ul = "", ldata = data.data.li, tpl = D.view(['h2','p','ul']), liTpl = D.templateString(D.View("li"),{li:D.View(['strong','span'])}); data.id && (s.id = data.id); for(var i =0,len = ldata.length;i<len;i++){ if(ldata[i].em || ldata[i].span){ ul += D.templateString(liTpl,ldata[i]); } } data.data.ul = ul; s.innerHTML = D.templateString(tpl,data.data); D.root.appendChild(s) }, "codePart":function(){}, "onlyTitle":function(){}, "guide":function(){} } //视图入口 D.init = function(){ //根据传输的视图类型创建视图 this.strategy[data.type](data); }
惰性模式
减少每执行时的重复分支判断,通过对对象重定义来屏蔽原对象中的分支判断。
//单体模式定义命名空间 var A = {}; A.on = function(dom,type,fn){ if (document.addEventListener) { return function(dom,type,fn){ document.addEventListener(type,fn,false); } }else if(document.attachEvent){ return function(dom,type,fn){ dom.attachEvent("on"+type,fn) } }else{ return function(dom,type,fn){ dom["on"+type] = fn; } } A.on(dom, type, fn) }; //第二种方式 A.on = function (dom, type, fn) { if (document.addEventListener) { return function (dom, type, fn) { document.addEventListener(type, fn, false); } } else if (document.attachEvent) { return function (dom, type, fn) { dom.attachEvent("on" + type, fn) } } else { return function (dom, type, fn) { dom["on" + type] = fn; } } }(); //两种方式都是让不必要的分支判断得到剥离。 /** * 创建XHR对象实例 */ function createXHR(){ if (typeof XMLHttpRequest != "undefined") { return new XMLHttpRequest(); }else if (typeof ActiveXObject != "undefined") { if (typeof arguments.callee.activeXString != "string") { var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"], i=0; len = versions.length; for(;i<len;i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex) {} } } }else{ throw new Error("您的浏览器并不支持Ajax"); } } //第一种优化方案 var createXHR = (function(){ if (typeof XMLHttpRequest != "undefined") { return function(){ return new XMLHttpRequest(); } }else if (typeof ActiveXObject != "undefined") { if (typeof arguments.callee.activeXString != "string") { var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i = 0; len = versions.length; for (; i < len; i++) { try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex) { } } } }else{ return function(){ throw new Error("您的浏览器并不支持Ajax") } } })(); //第二种优化方案 function createXHR(){ if (typeof XMLHttpRequest !="undefined") { createXHR = function(){ return new XMLHttpRequest(); } }else if(typeof ActiveXObject != "undefined"){ createXHR = function(){ if (typeof arguments.callee.activeXString != "string") { var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i = 0; len = versions.length; for (; i < len; i++) { try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex) { } } } } }else{ createXHR = function(){ throw new Error("您的浏览器并不支持Ajax") } } return createXHR; }
参与者模式
在特定的作用域中执行给定的函数,并且把参数原封不动的传递。例如网站的天气模块,一打开页面之后就定时从后端获取数据缓存下来,当用户打开查看天气时,立即展示天气信息。
/*** * 参与者模式 */ var B = {}; B.event.on = function(dom,type,fn,data){ if (dom.addEventListener) { dom.addEventListener(type,function(){ fn.call(dom,e,data); },false); }else if (dom.attachEvent) { dom.attachEvent("on" + type, function () { fn.call(dom, e, data); }); } } //函数绑定 function bind(fn, context) { var Slice = Array.prototype.slice, args = Slice.call(arguments, 2); return function () { var addArgs = Slice.call(arguments), AllArgs = addArgs.concat(args); return fn.apply(context, AllArgs); } } //函数柯里化 function curry(fn){ var Slice = Array.prototype.slice, args = Slice.call(arguments, 2); return function () { var addArgs = Slice.call(arguments), AllArgs = addArgs.concat(args); return fn.apply(context, AllArgs); } }
等待者模式
对多个异步进程监听,来触发未来发生的动作。等待者模式就是解决那些不确定先后完成的异步逻辑。
/*** * 等待者模式 */ //等待对象 var Waiter = function(){ var dfd = [], doneArr = [], failArr = [], slice = Array.prototype.slice, that = this; //监控对象 var Primise = function(){ //监控对象是否解决成功状态 this.resolved = false; //监控对象是否解决失败状态 this.rejected = false; } //监控对象 Primise.prototype = { resolve:function(){ //设置当前的监控对象解决成功 this.resolved = true; //没有监控对象就是直接取消执行 if (!dfd.length) { return; } //遍历所有注册的监控对象 for(var i = dfd.length-1;i>=0;i--){ //要是任意一个监控对象没有被解决或者解决失败没救返回 if (dfd[i]&&!dfd[i].resolved || dfd[i].rejected) { return; } //清除监控对象 dfd.splice(i,1); } //执行解决成功回调函数 _exec(doneArr); }, reject:function(){ //设置当前监控对象解决失败 this.rejected = true; //不存在监控对象就取消执行 if (!dfd.length) { return; } dfd.slice(0); _exec(failArr) } } //创建监控对象 that.Deferred = function(){ return new Primise(); } //回调执行方法 function _exec(arr){ var i =0, len = arr.length; for(;i<len;i++){ try { arr[i] && arr[i](); } catch (e) {} } } //监控异步方法 that.when = function(){ dfd = slice.call(arguments); var i = dfd.length; for(--i;i>=0;i--){ if (!dfd || dfd[i].resolved || dfd[i].rejected || !dfd[i] instanceof Primise) { dfd.splice(i,1) } } return that; }; //解决成功回调函数添加方法 that.done = function(){ doneArr = doneArr.concat(slice.call(arguments)); return that; }; //解决失败回调函数添加方法 that.fail = function(){ failArr = failArr.concat(slice.call(arguments)); return that; }; } //测试 var waiter = new Waiter() var first = function(){ var dtd = waiter.Deferred(); setTimeout(() => { console.log(11); dtd.resolve() }, 5000); return dtd; }(); var second = function(){ var dtd = waiter.Deferred(); setTimeout(() => { console.log(2222); dtd.resolve(); }, 10000); return dtd; }(); waiter.when(first,second) .done(function(){ console.log(999) },function(){ console.log(888) }) .fail(function(){ console.log(555) })
文章评论