版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuelian3015/article/details/89448019
技巧型设计模式是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)
})