$().ready(function() {
var cb = $.Callbacks();
setTimeout(function() {
alert(111)
cb.fire();
}, 2000);
cb.add(function() {//这里先把函数存到数组里面,当定时器里面触发fire()方法的时候,就会触发数组里面这个函数的调用
alert(222);
});
});
$().ready(function() {
var cb = $.Deferred();
setTimeout(function() {
alert(111)
cb.resolve();
}, 2000);
cb.done(function() {
alert(222);
});
});
setTimeout(function() {
alert(111)
}, 2000);
alert(222);
//这种情况,会先弹出2后弹出1,因为定时器是异步的,如果想要先弹1后弹2,可以降alert放到定时器内,但是如果是函数的情况先,想要函数按照一定顺序执行,如果也放定时器内的话,这时候,作用域就发生了改变;其二是如果都忘定时器里面放的话,那么代码会很臃肿,一个定时器内的代码
这种情况如果使用延迟对象管理一下异步,就会
==
$.ajax('xxx.php').done(function(){ alert('成功'); }).fail(function(){ alert('失败'); });
//上面这个ajax操作中,成功触发的是resolve,失败触发的是reject
//那么jq当中是怎么样做到这种映射关系的呢?
扫描二维码关注公众号,回复:
5050764 查看本文章
下面的图片是deferred和promise对象的关系,
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<style>
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-size: 32px;
background: #2C1C44;
font-family: sans-serif;
color: #FFF;
font-family: "Playfair Display", serif;
/*margin: 50px;*/
margin: 0;
overflow: hidden;
}
</style>
<script src="jquery-2.0.3.js"></script>
</head>
<body>
<script>
$().ready(function() {
jQuery.extend({
Deferred: function( func ) {
var tuples = [
// action, add listener, listener list, final state
[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory") ]
],
/*
*数组中Callbacks中的参数once和Memory的作用是:
看如下情况,如果是dfd.resolve()或dfd.reject(),那么成功/失败只会弹出一次,之后会弹的一直是111,原因是因为once,
如果是dfd.notify(); 则不同,会一直循环弹出111、失败
====情况1=====
var dfd = $.Deferred();
setInterval(function(){
alert(111);
//dfd.resolve();
//dfd.reject();
dfd.notify();
},1000);
dfd.done(function(){
alert('成功');
}).fail(function(){
alert('失败');
}).progress(function(){
alert('进度中');
});
====/情况1=====
====情况2=====
*在Callbacks对象中,有memory的情况下,add的过程中就调用了fire()方法,例如:
var cb = $.Callbacks('memory');
cb.add(function(){
alert(1);
});
cb.fire();
$('input').click(function(){
cb.add(function(){
alert(2);
});
})
上面的情况,弹出1的时候,不会弹出2,只有点击触发了input这个元素,才会弹出2,这里是add()添加函数进入数组的动作,但是因为有memory,所以就触发了fire()
====/情况2=====
====情况3======
var dfd = $.Deferred();
setTimeout(function(){
alert(111);
dfd.resolve();//执行这里的时候,状态已经触发
},1000);
dfd.done(function(){
alert('aaa');
});
$('input').click(function(){
dfd.done(function(){//点击的时候,done的的状态在之前已经触发了,所以这个done里面的操作会立即触发
alert('bbb');
});
});
这里的情况运用在于,第一次不触发,后面每次都会立即触发的业务情况中
====/情况3=====
*
*
*/
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
then: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var action = tuple[ 0 ],
fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred[ done | fail | progress ] for forwarding actions to newDefer
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
}
});
});
fns = null;
}).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
// Keep pipe for back-compat
promise.pipe = promise.then;
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],//对应的就是Callbacks函数
stateString = tuple[ 3 ];//这个是状态 如果是notify的话,那么stateString是否为undefined?
// promise[ done | fail | progress ] = list.add
promise[ tuple[1] ] = list.add;//回调对象的add方法,callbacks对象有个add方法,这里的add方法对应的就是Callbacks中的add方法,并且将和回调方法放到了promise对象下面
/*
*promise["done"] promise["fail"] promise["progress"] 这里做 映射,将Callbacks中的add方法映射到了primse上
*/
// Handle state
if ( stateString ) {
list.add(function() {
// state = [ resolved | rejected ]
state = stateString;
// [ reject_list | resolve_list ].disable; progress_list.lock
}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}
// deferred[ resolve | reject | notify ]
deferred[ tuple[0] ] = function() {//三个状态的方法添加到了deferred对象下面
deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
return this;
};
deferred[ tuple[0] + "With" ] = list.fireWith;//这里将Callbacks的fire方法映射给differed
});
// Make the deferred a promise
promise.promise( deferred );//promise.promise()==>这个方法将deferred对象作为参数传递进去,就是deferred继承了promise的所有的方法,并且,还比promise还多出三个状态方法
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
when: function( subordinate /* , ..., subordinateN */ ) {
var i = 0,
resolveValues = core_slice.call( arguments ),
length = resolveValues.length,
// the count of uncompleted subordinates
remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
// Update function for both resolve and progress values
updateFunc = function( i, contexts, values ) {
return function( value ) {
contexts[ i ] = this;
values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
if( values === progressValues ) {
deferred.notifyWith( contexts, values );
} else if ( !( --remaining ) ) {
deferred.resolveWith( contexts, values );
}
};
},
progressValues, progressContexts, resolveContexts;
// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
progressValues = new Array( length );
progressContexts = new Array( length );
resolveContexts = new Array( length );
for ( ; i < length; i++ ) {
if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
resolveValues[ i ].promise()
.done( updateFunc( i, resolveContexts, resolveValues ) )
.fail( deferred.reject )
.progress( updateFunc( i, progressContexts, progressValues ) );
} else {
--remaining;
}
}
}
// if we're not waiting on anything, resolve the master
if ( !remaining ) {
deferred.resolveWith( resolveContexts, resolveValues );
}
return deferred.promise();
}
});
//源码中,讲三个回调方法放到promise对象下面,而将三个状态方法放到了deferred对象下面,promise对象和deferred对象都是延迟对象,那么promise对象和deferred对象,他们俩的关系是什么和有什么区别呢?
/*
function aaa(){
var dfd = $.Deferred()
setTimeout(function(){
dfd.resolve();
},1000);
return dfd;//这里的延迟对象是Deferred对象,因为这个对象下面有表示状态的方法,所以能改变状态,
}
var newDfd = aaa();
newDfd.done(function(){
alert('成功');
}).fail(function(){
alert('失败');
});
newDfd.reject();
上面的情况,因为dfd.resolve();要延迟一秒后才能执行,而newDfd.reject();先执行,已经先把状态改成了reject的状态所以上面resolve的状态就不会再触发了。。。那么怎么样才能做到外面修改不了这个状态呢?
只要将aaa函数中的return 改成return dfd.promise();就可以不让外部更改状态,return dfd.promise()这时候,调用Deferred对象的promise,因为没有传参数,所以,这个时候是promise对象,promise对象没有对应状态的方法,所以,外部改不了方法
*/
});
</script>
</body>
</html>