js-jQuery中的Callbacks、Deferred和When对象详解(1)
来源:互联网 发布:文华行情软件 编辑:程序博客网 时间:2024/06/05 22:42
终于抽出点时间来讲解一下jQuery中的Callbacks/Deferred这几个对象了,不过篇幅可能过长,讲到哪儿是哪儿吧。
$.Deferred方法每次调用都会返回一个Deferred对象。Deferred对象用于异步方法链式调用,让编程方式从传统的回调函数中解脱出来——javascript的回调深度一直都是遭人诟病。
首先从最底层Callbacks对象讲起,看简化后的源码:
Callbacks: function(options){var list = [],firing, fired, memory,firingIndex, firingStart, firingLength,options = options || {},stack = !options.once && [],fire = function(data){memory = options.memory && data;firingIndex = firingStart || 0;firingStart = 0;fired = true;firingLength = list.length;firing = true;for(; firingIndex < firingLength; firingIndex++){if(list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse === true){memory = false; // To prevent further calls using addbreak;}}firing = false;if(list){if(stack){if(stack.length){fire(stack.shift());}}else if(memory){list = [];//if options.once then disable it.}else{self.disable();}}},self = {add: function(){if(list){var start = list.length;(function _add(args){iBen.each(args, function(arg){if(jQuery.isFunction(arg)){list.push(arg);} else if ( arg && arg.length && !jQuery.isString(arg) ) {// Inspect recursively_add( arg );}});})(arguments);if(firing){firingLength = list.length;}else if(memory){firingStart = start;fire(memory);}}return this;},// Remove a callback from the listremove: function() {if ( list ) {jQuery.each( arguments, function( _, arg ) {var index;while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {list.splice( index, 1 );// Handle firing indexesif ( firing ) {if ( index <= firingLength ) {firingLength--;}if ( index <= firingIndex ) {firingIndex--;}}}});}return this;},fireWith: function(context, args){if(list){args = [context, args];if(firing){stack.push(args);}else{fire(args);}}return this;},fire: function(){return this.fireWith(this, arguments);},disable: function(){list = stack = memory = undefined;return this;}};return self;}
我就不逐行写注释了,简单来说最后返回的self才是真正的Callbacks对象,公布出的接口主要也就是add、fire、fireWith、remove这几个方法。
add方法将函数添加到回调列表list中。
_add方法在参数是数组的时候会递归调用。
如果正在调用的话,修正回调列表的长度。
如果不是调用中且没有指明once选项同时指定了memory选项去记住最后一次调用的参数时则修正开始调用索引去立即调用。
fire方法实际调用的是Callbacks中的fire方法。
调用fireWith-指定默认环境为self和参数。
将参数进行格式化,如果正在调用则放到stack中等待当前调用列表完成后调用,否则立即调用。
进行fire时会通过options.once判断改列表是否只调用一次,是则调用结束后disable掉该回调列表,否则查看stack中是否有函数等待回调,如果指定了memory选项去记录了最后一次调用的参数,则清空该回调列表。
remove方法将对应的函数从回调列表中移除,并修正firing的索引。
整个Callbacks的流程就是这样,其实Callbacks可以看做为一个观察者模式。看观察者模式的代码:
observer : (function(box){var Publisher={subscribe: function(fn, context, type){type = type || 'any';fn = iBen.isFunction(fn) ? fn: context[fn];if (iBen.isUndefined(this.subscribers[type]))this.subscribers[type] = [];this.subscribers[type].push([fn, context]);},unsubscribe: function(fn, type){type = type || 'any';var that = this;this.subscribers[type].splice($A(this.subscribers[type]).indexOf(fn), 1);},shutdown: function(type){type = type || 'any';this.subscribers[type] = [];},publish: function(){var args, type = arguments[arguments.length-1];type = iBen.isString(type)? type : 'any';args = _slice.call(arguments, 0);this.subscribers[type]&&iBen.each(this.subscribers[type], function(object){object[0].apply(object[1], args);});}};return function(o){o = o || {};iBen.extend(o, Publisher, true, 'function');o.subscribers={any : []};return o;};})()基本上工作的流程是一样的,都是将对应的事件添加到队列中去,然后通过fire/publish的方式调用整个回调列表,除了Callbacks对象可以在函数的执行中通过self对象提供的接口更细粒度的控制和获取回调列表的运行状态。
Callbacks对象相对比较直观,下面看jQuery的Deferred对象,不过在这之前最好先自行了解一下Promise/A+规范:
要求
Promise的状态
一个 Promise 必须处于等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)这三种状态中的一种之中。
处于等待态时,promise :
- 可以迁移至执行态或拒绝态
处于执行态时,promise :
- 不能迁移至其他任何状态
- 必须拥有一个不可变的值
处于拒绝态时,promise:
- 不能迁移至其他任何状态
- 必须拥有一个不可变的据因
这里的不可变指的是恒等(即可用 ===
判断相等),而不是意味着更深层次的不可变
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") ]],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 fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];// deferred[ done | fail | progress ] for forwarding actions to newDeferdeferred[ 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[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );}});});fns = null;}).promise();},promise: function( obj ) {return obj != null ? jQuery.extend( obj, promise ) : promise;}},deferred = {};jQuery.each( tuples, function( i, tuple ) {var list = tuple[ 2 ],stateString = tuple[ 3 ];// promise[ done | fail | progress ] = list.addpromise[ tuple[1] ] = list.add;// Handle stateif ( 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[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );return this;};deferred[ tuple[0] + "With" ] = list.fireWith;});promise.promise( deferred );if ( func ) {func.call( deferred, deferred );}// All done!return deferred;}
可以看出,jQuery并没有完全按照Promise规范来构建promise对象。jQuery的三种状态分别为:resolved,rejected和处理中状态,而对应promise规范中的执行状态和被拒绝状态时状态不可改变的要求:
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 );}i^1会讲0和1的索引对调(在我的另一篇博文中有提到),在执行resolve时会将reject列表disable掉,同样在执行reject中会disable掉resolve列表,并将notify列表lock住,以防止状态的改变。
Deferred对象里面主要包含两个部分:
1、promise对象
在遍历tuples时会将对应的Callbacks对象的add方法作为promise的done | fail | progress。
2、deferred对象
在遍历tuples时会将对应的Callbacks对象的fireWith方法作为resolveWith | rejectWith | notifyWith
调用promise.promise将deferred对象做成一个promise对象。
最后返回deferred对象。
大概讲到这里吧,剩下的then方法和when对象留到下次讲解。
有其他疑问或错误之处欢迎之处~
- js-jQuery中的Callbacks、Deferred和When对象详解(1)
- js-jQuery中的Callbacks、Deferred和When对象详解(2)
- jquery中的工具方法--Deferred和when
- 详解Jquery deferred 对象
- jquery中的deferred详解
- jquery的when和Deferred方法
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- jQuery的deferred对象详解
- Java关键字final、static使用总结
- 因特尔又要加入手机芯片市场了
- 谁能开发一种用汉子编程的语言就牛逼了。
- c++设计模式(工厂方法模式)
- 【Unity基础知识③】MSIL、变量、声明变量与内存的关系
- js-jQuery中的Callbacks、Deferred和When对象详解(1)
- ssh连接缓慢的一个解决办法
- Tomcat下获取当前类的路径中含有空格的解决方案
- 微信公众号H5游戏平台完整源码放送给大家
- 如何判断一个字符串是java代码还是英文单词?
- RevitAPI: 如何获取某个材质参数?
- 哈希表总结
- Eclipse生成jar包
- IOS 集合视图指南1:介绍