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队列只执行一次。
代码:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> <script type="text/javascript"> function show(data) {
$("body").append('<li>' + data + '</li>')
} function fn1(value) {
show(value);
} function fn2(value) {
fn1("fn2 says: " + value);
return false;
} var callbacks = $.Callbacks();
callbacks.add(fn1);
// outputs: foo!
callbacks.fire("foo!");
callbacks.add(fn2);
// outputs: bar!, fn2 says: bar!
callbacks.fire("bar!"); </script> </body>
</html>
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执行回调。
代码:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://img.mukewang.com/down/540812440001e40e00000000.js" type="text/javascript"></script>
<title></title>
</head>
<body> <script type="text/javascript"> var optionsCache = {};
var rnotwhite = (/\S+/g);
// Convert String-formatted options into Object-formatted ones and store in cache function show(data) {
if (typeof data === 'object') {
for (var key in data) {
$("body").append('<li>key->' + key + '; value->'+ data[key] +'</li>')
}
} else {
$("body").append('<li>' + data + '</li>')
}
} function createOptions(options) {
var object = optionsCache[options] = {};
jQuery.each(options.match(rnotwhite) || [], function(_, flag) {
object[flag] = true;
});
return object;
} function callback(options) {
options = typeof options === "string" ?
(optionsCache[options] || createOptions(options)) :
jQuery.extend({}, options);
show(options)
} callback('once memory') } </script> </body>
</html>
JQuery源码解析(九)的更多相关文章
- JQuery源码解析(一)
写在前面:本<JQuery源码解析>系列是基于一些前辈们的文章进行进一步的分析.细化.修改而写出来的,在这边感谢那些慷慨提供科普文档的技术大拿们. 要查阅JQ的源文件请下载开发版的JQ.j ...
- jQuery 源码解析二:jQuery.fn.extend=jQuery.extend 方法探究
终于动笔开始 jQuery 源码解析第二篇,写文章还真是有难度,要把自已懂的表述清楚,要让别人听懂真的不是一见易事. 在 jQuery 源码解析一:jQuery 类库整体架构设计解析 一文,大致描述了 ...
- jquery源码解析:代码结构分析
本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94) 定义了一些变量和函数, jQuery = function() ...
- jquery 源码解析
静态与实力方法共享设计 遍历方法 $(".a").each() //作为实例方法存在 $.each() //作为静态方法存在 Jquery源码 jQuery.prototype = ...
- 三.jQuery源码解析之jQuery的框架图
这张图片是对jQuery源码截图,一点一点拼出来的. 现在根据这张图片来对jQuery框架做一些说明. 一.16~9404行可以发现,最外层是一个自调用函数.当jQuery初始化时,这个自调用函数包含 ...
- jQuery源码解析资源便签
最近开始解读jQuery源码,下面的链接都是搜过来的,当然妙味课堂 有相关的一系列视频,长达100多期,就像一只蜗牛慢慢爬, 至少品读三个框架,以后可以打打怪,自己造造轮子. 完全理解jQuery源代 ...
- jquery源码解析:addClass,toggleClass,hasClass详解
这一课,我们将继续讲解jQuery对元素属性操作的方法. 首先,我们先看一下这几个方法是如何使用的: $("#div1").addClass("box1 box2&quo ...
- jquery源码解析:jQuery数据缓存机制详解2
上一课主要讲了jQuery中的缓存机制Data构造方法的源码解析,这一课主要讲jQuery是如何利用Data对象实现有关缓存机制的静态方法和实例方法的.我们接下来,来看这几个静态方法和实例方法的源码解 ...
- jquery源码解析:jQuery数据缓存机制详解1
jQuery中有三种添加数据的方法,$().attr(),$().prop(),$().data().但是前面两种是用来在元素上添加属性值的,只适合少量的数据,比如:title,class,name等 ...
- jquery源码解析:jQuery工具方法when详解
我们先来看when方法是如何使用的: var cb = $.when(); //when方法也是返回一个延迟对象,源码是return deferred.promise();返回的延迟对象不能修改状 ...
随机推荐
- Symmetric Tree [LeetCode]
Problem description: http://oj.leetcode.com/problems/symmetric-tree/ Basic idea: Both recursive and ...
- 《JavaScript权威指南》读书笔记(四)
日期:2015-12-06 事件传播:1.捕捉阶段2.运行阶段3.起泡阶段cookie和客户端持久性::HTML5引入了web应用缓存.LocalStorage.SessionStorage:使用XM ...
- input覆盖select实现select可写可选择
1.有时需要一个select选择框,但是对select选择框希望是既可以选择也可以进行输入.下边的代码就是在select选择框上放了一个input框,覆盖在select上面.实现伪装的select效果 ...
- Java 中equals和toString()方法重写
1,equals方法 (1)什么时候需要重写? 如果希望不同内存但相同内容的两个对象equals时返回true,则需要重写equals (2)怎么重写? class A { public int i; ...
- __attribute__特性介绍以及变量和函数特定布局设置
ARM的MDK编译__attribute__介绍:http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0348bc/Ciafc ...
- 用js创建XMLHttpRequest对象池[转]
//使用literal语法定义一个对象:XMLHttp var XMLHttp = { //定义第一个属性,该属性用于缓存XMLHttpRequest对象的数组 XMLHttpRequestPool: ...
- HDU 3567 Eight II 打表,康托展开,bfs,g++提交可过c++不可过 难度:3
http://acm.hdu.edu.cn/showproblem.php?pid=3567 相比Eight,似乎只是把目标状态由确定的改成不确定的,但是康托展开+曼哈顿为h值的A*和IDA*都不过, ...
- HDU 1166 单点更新,区间求和
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submis ...
- UIKit-3347.44.2/UICollectionView.m:3443
Assertion failure in -[UICollectionView _dequeueReusableViewOfKind:withIdentifier:forIndexPath:viewC ...
- “人少也能办大事”---K2 BPM老客户交流会
主题:固铂轮胎工作流项目分享-K2 SmartForm下的工作流快速开发 嘉宾:王彦(固铂轮胎IT资深经理) 国内业务规模越来越大,流程越来越复杂,跨部门跨组织的流程纸质审批非常复杂,内控的要求越来越 ...