JQuery源码解析(九)

网友投稿 530 2022-10-06

JQuery源码解析(九)

jQuery回调对象

jQuery.Callbacks一般开发者接触的很少,虽然jQuery向开发者提供了外部接口调用,但是$.Callbacks()模块的开发目的是为了给内部$.ajax() 和 $.Deferred()模块提供统一的基本功能组件。它可以用来作为类似基础定义的新组件的功能。

jQuery.Callbacks是jquery在1.7版本之后加入的,是从1.6版中的_Deferred对象中抽离的,主要用来进行函数队列的add、remove、fire、lock等操作,并提供once、memory、unique、stopOnFalse四个option进行一些特殊的控制。

这个函数常见的应用场景是事件触发机制,也就是设计模式中的观察者模式的发布、订阅机制,目前Callbacks对象用于queue、ajax、Deferred对象中

看官网提供的demo:

function fn1(value) { console.log(value);}function fn2(value) { fn1("fn2 says: " + value); return false;}

可以将上述两个方法作为回调函数,并添加到 $.Callbacks 列表中,并按下面的顺序调用它们:

var callbacks = $.Callbacks();callbacks.add(fn1);// outputs: foo!callbacks.fire("foo!");callbacks.add(fn2);// outputs: bar!, fn2 says: bar!callbacks.fire("bar!")

这样做的结果是,当构造复杂的回调函数列表时,将会变更很简单。可以根据需要,很方便的就可以向这些回调函数中传入所需的参数。

上面的例子中,我们使用了 $.Callbacks() 的两个方法: .add() 和 .fire()。

.add() 支持添加新的回调列表, 而.fire() 提供了一种用于处理在同一列表中的回调方法的途径。

另一种方法是$.Callbacks 的.remove()方法,用于从回调列表中删除一个特定的回调。下面是.remove()使用的一个例子:

var callbacks = $.Callbacks();callbacks.add( fn1 );// outputs: foo!callbacks.fire( "foo!" );callbacks.add( fn2 );// outputs: bar!, fn2 says: bar!callbacks.fire( "bar!" );callbacks.remove( fn2 );// only outputs foobar, as fn2 has been removed.callbacks.fire( "foobar" );

这个运用内部就是观察者模式的一种设计实现,只是相对比较复杂。我们看看jQuery的回调函数到底为哪些模块服务?

异步队列模块:

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")] ],………….

队列模块

_queueHooks: function(elem, type) { var key = type + "queueHooks"; return data_priv.get(elem, key) || data_priv.access(elem, key, { empty: jQuery.Callbacks("once memory").add(function() { data_priv.remove(elem, [type + "queue", key]); }) });}

Ajax模块

ajax: function(url, options) { //省略代码 deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory") ..............}

不难发现jQuery.Callbacks还提供“once memory”等参数用来处理:

once: 确保这个回调列表只执行( .fire() )一次(像一个递延 Deferred)。

memory: 保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred)。

unique: 确保一次只能添加一个回调(所以在列表中没有重复的回调)。

stopOnFalse: 当一个回调返回false 时中断调用。

var callbacks = $.Callbacks('once');callbacks.add(function() { alert('a');})callbacks.add(function() { alert('b');})callbacks.fire(); //输出结果: 'a' 'b'callbacks.fire(); //未执行

once的作用是使callback队列只执行一次。

代码:

jQuery回调模块结构

整个$.Callbacks的源码很少,它是一个工厂函数,使用函数调用(非new,它不是一个类)创建对象,它有一个可选参数flags用来设置回调函数的行为,

对外的接口也就是self的返回。

jQuery.Callbacks()的API列表如下:

callbacks.add() :回调列表中添加一个回调或回调的集合。callbacks.disable() :禁用回调列表中的回调。callbacks.disabled() :确定回调列表是否已被禁用。 callbacks.empty() :从列表中删除所有的回调。callbacks.fire() :用给定的参数调用所有的回调。callbacks.fired() :访问给定的上下文和参数列表中的所有回调。 callbacks.fireWith() :访问给定的上下文和参数列表中的所有回调。callbacks.has() :确定列表中是否提供一个回调。callbacks.lock() :锁定当前状态的回调列表。callbacks.locked() :确定回调列表是否已被锁定。callbacks.remove() :从回调列表中的删除一个回调或回调集合。

源码结构:

jQuery.Callbacks = function(options) { options = typeof options === "string" ? (optionsCache[options] || createOptions(options)) : jQuery.extend({}, options); //实现代码 fire = function() {} self = { add: function() {}, remove: function() {}, has: function(fn) {}, empty: function() {}, disable: function() {}, disabled: function() {}, lock: function() {}, locked: function() {}, fireWith: function(context, args) {}, fire: function() {}, fired: function() {} }; return self;};

整个结构要分三部分:

Options参数缓存

内部fire触发器的设计

外部

参数的缓存设计

Callbacks是可以是接受的字符串的组合传参数,可以使用空格分割,代码如下:

var opts = 'unique memory';var object = {}jQuery.each(opts.match(/\S+/g) || [], function(_, flag) { object[flag] = true;});

这样的操作其实是不需要重复的,所以我们可以设计一个缓存池,用来储存重复的操作:

var optionsCache = {};function createOptions(options) { var object = optionsCache[options] = {}; jQuery.each(options.match(rnotwhite) || [], function(_, flag) { object[flag] = true; }); return object;}

所以我们传递参数的时候,如果参数是字符串,我们可以直接从optionsCache缓存中去查找:

options = typeof options === "string" ? ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options );

接口的设计:

通过学习了观察者模式的思路,我们知道callback需要在内部维护着一个list的队列数组,用于保存订阅的对象数据。同时也需要提供了add、remove、fire等订阅、发布、删除类似的接口。

那么我们代码是不是很简单是就是把订阅对象给push给内部list列表?

实现思路就是: 构建一个存放回调的数组,如​​var list = []​​,通过闭包使这条回调数组保持存在。添加回调时,将回调push进list,执行则遍历list执行回调。

代码:

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:如何利用小程序+插件快速开发app?
下一篇:小程序容器如何解决软件开发三大痛点?
相关文章

 发表评论

暂时没有评论,来抢沙发吧~