jQuery源码分析系列(39) : 动画队列
data函数在jQuery中只有短短的300行代码,非常不起点 ,剖析源码的时候你会发现jQuery只要在有需要保存数据的地方无时无刻不依赖这个基础设施
动画会调用队列,队列会调用data数据接口还保存队列里面的的动画数据
所以我们在自习回顾下关于数据缓存
//These may be used throughout the jQuery core codebase
//存数据的
//用户使用
data_user = new Data();
//存储对象
//jQuery内部私有
//用来存事件的, 如click事件那种
data_priv = new Data();
data在jQuery中有两种
一个是用来存数据的, 对应的对象分别是
存储对象: data_user 获取与设置方法: $.data(el, key, value)
另一个是用来存事件的,动画数据的
存储对象: data_priv 获取与设置方法: $._data(el, key, value)
data_user
和data_priv
, 就如其名, 一个是用户用的, 一个是jQuery私有的, 他们都是一个叫Data的实例对象
为什么要设置这2个数据接口类?
jQuery的设置都是维护一个jQuery的数据对象,所以
只是实现data的接口,比如:
$('#aaron').data('key', 'value')
实现链式的.data接口,这种很简单,我们可以把简单的数据缓存到jquery内部的这个对象上
方法可以这样实现
直接在实例上fn的接口上扩充
$.fn.data = function(k, v) {
return this.each(function() {
this[key] = v //把接口data的value保存在dom对象上
})
return this
}
这个很简单把数据直接保存在dom对象上
当然针对基本类型这样处理当然也是可以的,如果是引用类型,函数对象呢?这样处理可以吗?
$('#aaron').data('nodeValue', '11111') $('#aaron').data('key', function(){
//操作
})
问题来了:
1:这样会更改DOM本身的属性值,当然能不能生效还不说
2:传递可是引用类型哦,不靠谱的内存回收,说不定就溢出了
3:数据暴露,容易被直接改写
如何解决这些问题? jQuery就引入了数据对象这个概念
先不管内部怎么实现,先看节点的属性
多了一个灰色的自定义的key与value
灰色意味着不能通过for枚举出来,这种设置在ES5中,是有API直接支持了
// If not, create one
if (!unlock) {
unlock = Data.uid++;
// Secure it in a non-enumerable, non-writable property
try {
descriptor[this.expando] = {
value: unlock
};
Object.defineProperties(owner, descriptor);
// Support: Android < 4
// Fallback to a less secure definition
} catch (e) {
descriptor[this.expando] = unlock;
jQuery.extend(owner, descriptor);
}
}
看注释就清晰了,这个属性是受保护的,不能被改写
OK了。通过这样一个唯一的桥接标志,我们可以做一个ORM的映射了,让dom与一个数据缓存接口产生一一对应的关系
动画队列用到的数据缓存
jQuery为了实现动画队列的链式调用,所以必须先在实例就是原型上先扩展一个方法啊,然后在内部才能调用底层的方法
当然jQuery基本所有的层次都是这样的结构,除了链式之外,还可以把具体的实例方法与原型方法通用
//静态
jQuery.extend
//实例
.extend
动画的实例方法
this.queue(optall.queue, doAnimation);
调用实例方法中基于动画的扩展接口
jQuery.fn.extend({
queue
dequeue
delay
clearQueue
promise
queue: function(type, data) {
var setter = 2;
//修正type, 默认为表示jquery动画的fx, 如果不为"fx",
//即为自己的自定义动画, 一般我们用"fx"就足够了.
if (typeof type !== "string") {
data = type;
type = "fx";
setter--;
} //只有动画的回调
// div.slideToggle(1000);
// div.slideToggle("fast");
// div.animate({left:'-=200'},1500);
// div.queue('fx')
if (arguments.length < setter) {
return jQuery.queue(this[0], type);
} return data === undefined ?
this :
this.each(function() {
//调用基础队列
//设置动画队列缓存
//并返回队列总数
var queue = jQuery.queue(this, type, data); // ensure a hooks for this queue
jQuery._queueHooks(this, type); //直接执行动画队列
//防止在执行函数的时候, 这里又进行dequeue操作, 这样会同时执行2个函数, 队列就不受控制了.
if (type === "fx" && queue[0] !== "inprogress") {
//如果队列没有被锁住, 即此时没有在执行dequeue. 移出队列里第一个函数并执行它.
jQuery.dequeue(this, type);
}
});
},
实例的queue接口只是做了2个情况的判断,一种是传递fx,一种是设置队列,底层还是通过jQuery.queue静态方法处理的
分析一组动画:
div.show(1000);
div.hide(2000)
div.show(3000)
1 有时间参数的接口,是肯定需要执行动画的,同一个接口上有多个动画接口,那么就会意味着需要队列来管理执行顺序
2 管理队列引入数据缓存,缓存需要载体node节点,所以动画的扩展的接口在最上层设计是可以直接跟DOM链式
逻辑上肯定是线性的执行,show执行完毕,然后取出hide执行,完毕后在取出show执行
那么动画的调用是如何组织的?
理论上3个动画,在cache中有3个缓存的data我们查看下
为了便于查看,我把代码改了下 增加了一个标示 Aaron 对应的是时间
在执行div.show(3000)的时候,我们查看下缓存
发现0位置的div.show(1000);被inprogress给替代了
可以猜测下第一个动画已经在开始执行了,那么它在队列中会用一个占位符用来通知后面,我这个动画还在进行,后面的动画先等等
inprogress”进程锁是这样工作的:
如果是dequeue操作, 去掉锁, 执行队列里的函数, 同时给队列加上锁. 如果是queue操作, 要看锁的状态, 如果被锁上了, 就只执行队列的添加操作. 不再调用dequeue.其实dequeue和queue都可以执行队列里的第一个函数.queue操作添加完队列之后, 会调用dequeue方法去执行函数.
用dequeue执行函数的时候, 这时候如果又用queue触发dequeue的话, 很可能同时有2个函数在执行. 队列就失去一大半意义了(还是可以保证顺序, 但是2个动画会同时执行).不过这个锁只能保证在dequeue的时候, 不被queue操作意外的破坏队列.
如果人为的同时用2个dequeue, 还是会破坏动画效果的. 所以要把fn写在回调函数里
我们在第一次做push的时候就会开始执行了动画,这样可以让速度更优
.queue(1000) , .queue(2000) , queue(3000)
if (type === "fx" && queue[0] !== "inprogress") {
//如果队列没有被锁住, 即此时没有在执行dequeue. 移出队列里第一个函数并执行它.
jQuery.dequeue(this, type);
}
当第一个动画执行完毕后,那么必须有一个回调通知这个去把队列中下一个执行给取出来,然后要删掉这个占位,依次循环
opt.complete = function() {
if (jQuery.isFunction(opt.old)) {
opt.old.call(this);
} if (opt.queue) {
jQuery.dequeue(this, opt.queue);
}
};
所以可见,动画的执行其实最终是依赖queue与dequeue的处理,只是说在执行开始与执行完毕做了一个流程的控制
具体动画内部怎么执行的,从下章开始分析
jQuery源码分析系列(39) : 动画队列的更多相关文章
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
- [转]jQuery源码分析系列
文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaro ...
- jQuery源码分析系列(转载来源Aaron.)
声明:非本文原创文章,转载来源原文链接Aaron. 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAa ...
- jQuery源码分析系列——来自Aaron
jQuery源码分析系列——来自Aaron 转载地址:http://www.cnblogs.com/aaronjs/p/3279314.html 版本截止到2013.8.24 jQuery官方发布最新 ...
- jQuery源码分析系列(37) : Ajax 总结
综合前面的分析,我们总结如下3大块: jQuery1.5以后,AJAX模块提供了三个新的方法用于管理.扩展AJAX请求 前置过滤器 jQuery. ajaxPrefilter 请求分发器 jQuery ...
- jQuery源码分析系列(36) : Ajax - 类型转化器
什么是类型转化器? jQuery支持不同格式的数据返回形式,比如dataType为 xml, json,jsonp,script, or html 但是浏览器的XMLHttpRequest对象对数据的 ...
- jQuery源码分析系列(38) : 队列操作
Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Qu ...
- jQuery源码分析系列(31) : Ajax deferred实现
AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展 ajax请求的流程: 1.通过 new XMLHttpRequest 或其它的 ...
- jQuery源码分析系列 : 整体架构
query这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery又给扫一遍 我也不会照本宣科的翻译源码,结合自己的实际经验一起拜读吧! ...
随机推荐
- 解决svn uuid变更问题
简介: 今天在snv根目录下重新定位上传的url,更改后出现如下错误 .可以看到,原来Repository创建者的uuid是前者,而现在我操作的是后者的uuid.因此,目前的操作办法是 使用相关命令更 ...
- [NOIP2016]愤怒的小鸟 D2 T3 状压DP
[NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...
- phpcms文章点击量统计方法
phpcms用户广大,很好用,很傻瓜.设计思路也很好,对cms的常见功能都有设计,可以作为自己开发的参考. 最近看了下phpcms的源码关于文章点击量统计的这块,自己记录下. 默认文章点击量显示的位置 ...
- 【转】Oracle索引HINT的使用
转自:Oracle索引HINT的使用 存储在数据库中数据的分布情况开发人员或管理员比Oracle优化器更加的清楚,在优化器不能作出最有查询路径选择的情况下,使用HINT(提示)人为的固定查 ...
- [ACM训练] 算法初级 之 数据结构 之 栈stack+队列queue (基础+进阶+POJ 1338+2442+1442)
再次面对像栈和队列这样的相当基础的数据结构的学习,应该从多个方面,多维度去学习. 首先,这两个数据结构都是比较常用的,在标准库中都有对应的结构能够直接使用,所以第一个阶段应该是先学习直接来使用,下一个 ...
- 读取hdfs文件之后repartition 避免数据倾斜
场景一: api: textFile("hfds://....").map((key,value)).reduceByKey(...).map(实际的业务计算逻辑) 场景:hdf ...
- Android -- 软键盘
1. 应用启动后,自动打开软键盘 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD ...
- 插头dp
插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...
- Avoiding InvokeRequired
Just read a good article to do cross-thread calling in an easy and elegant way. It is amazing for it ...
- Meta标签介绍
Meta标签写法与作用 meta标签是在HTML网页源代码中一个重要的html标签.meta位于head区的辅助性标签,提供用户不可用的信息. META标签用来描述一个HTML网页文档的属性,例 ...