jQuery源码学习之Callbacks
jQuery源码学习之Callbacks
jQuery的ajax
、deferred
通过回调实现异步,其实现核心是Callbacks
。
使用方法
使用首先要先新建一个实例对象。创建时可以传入参数flags
,表示对回调对象的限制,可选值如下表示。
stopOnFalse
:回调函数队列中的函数返回false
时停止触发once
:回调函数队列只能被触发一次memory
:记录上一次触发队列传入的值,新添加到队列中的函数使用记录值作为参数,并立即执行。unique
:函数队列中函数都是唯一的
var cb = $.Callbacks('memory');
cb.add(function(val){console.log('1: ' + val)
})
cb.fire('callback')
cb.add(function(val){console.log('2: ' + val)
})
// console输出
1: callback
2: callback
Callbacks
提供了一系列实例方法来操作队列和查看回调对象的状态。
add
: 添加函数到回调队列中,可以是函数或者函数数组remove
: 从回调队列中删除指定函数has
: 判断回调队列里是否存在某个函数empty
: 清空回调队列disable
: 禁止添加函数和触发队列,清空回调队列和上一个传入的值disabled
: 判断回调对象是否被禁用lock
: 禁用fire
,若memory非空则同时add无效locked
: 判断是否调用了lock
fireWith
: 传入context
和参数,触发队列fire
: 传入参数触发对象,context
是回调对象
源码解析
$.Callback()
方法内部定义了多个局部变量和方法,用于记录回调对象的状态和函数队列等,返回self
,在self
实现了上述回调对象的方法,用户只能通过self
提供的方法来更改回调对象。这样的好处是保证除了self
之外,没有其他修改回调对象的状态和队列的途径。
其中,firingIndex
为当前触发函数在队列中的索引,list
是回调函数队列,memory
记录上次触发的参数,当回调对象实例化时传入memory
时会用到,queue
保存各个callback执行时的context和传入的参数。self.fire(args)
实际是self.fireWith(this,args)
,self.fireWith
内部则调用了在Callbacks
定义的局部函数fire
。
...// 以下变量和函数 外部无法修改,只能通过self暴露的方法去修改和访问var // Flag to know if list is currently firingfiring,// Last fire value for non-forgettable lists// 保存上一次触发callback的参数,调用add之后并用该参数触发memory,// Flag to know if list was already firedfired,// Flag to prevent firing// locked==true fire无效 若memory非空则同时add无效locked,// Actual callback list// callback函数数组list = [],// Queue of execution data for repeatable lists// 保存各个callback执行时的context和传入的参数queue = [],// Index of currently firing callback (modified by add/remove as needed)// 当前正触发callback的索引firingIndex = -1,// Fire callbacksfire = function() {...},// Actual Callbacks objectself = {// Add a callback or a collection of callbacks to the listadd: function() {...},...// Call all callbacks with the given context and argumentsfireWith: function( context, args ) {if ( !locked ) {args = args || [];args = [ context, args.slice ? args.slice() : args ]; // :前为args是数组,:后是stringqueue.push( args );if ( !firing ) {fire();}}return this;},// Call all the callbacks with the given argumentsfire: function() {self.fireWith( this, arguments );return this;},...}
通过self.add
添加函数到回调队列中,代码如下。先判断是否memory
且非正在触发,如果是则将fireIndex
移动至回调队列的末尾,并保存memory
。接着使用立即执行函数表达式实现add函数,在该函数内遍历传入的参数,进行类型判断后决定是否添加到队列中,如果回调对象有unique
标志,则还要判断该函数在队列中是否已存在。如果回调对象有memory
标志,添加完毕之后还会触发fire
,执行新添加的函数。
add: function() {if ( list ) {// If we have memory from a past run, we should fire after adding// 如果memory非空且非正在触发,在queue中保存memory的值,说明add后要执行fire// 将firingIndex移至list末尾 下一次fire从新add进来的函数开始if ( memory && !firing ) {firingIndex = list.length - 1;queue.push( memory );}( function add( args ) {jQuery.each( args, function( _, arg ) {// 传参方式为add(fn)或add(fn1,fn2)if ( jQuery.isFunction( arg ) ) {/*** options.unique==false* 或* options.unique==true&&self中没有arg*/if ( !options.unique || !self.has( arg ) ) {list.push( arg );}} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {// 传参方式为add([fn...]) 递归// Inspect recursivelyadd( arg );}} );} )( arguments ); //arguments为参数数组 所以add的第一步是each遍历//添加到list后若memory真则fire,此时firingIndex为回调队列的最后一个函数if ( memory && !firing ) {fire();}}return this;}
fire
、fireWith
方法内部实际调用了局部函数fire
,其代码如下。触发时,需要更新fired
和firing
,表示已触发和正在触发。通过for循环执行队里中的函数。结束循环后,将firingIndex
更新为-1,表示下次触发从队列中的第一个函数开始。遍历在fireWith
中更新过的queue
,queue
是保存数组的数组,每个数组的第一个元素是context
,第二个元素是参数数组。执行函数时要是否返回false
且回调对象有stopOnFalse
标志,如果是则停止触发。
// Fire callbacksfire = function() {// Enforce single-firing// 执行单次触发locked = locked || options.once;// Execute callbacks for all pending executions,// respecting firingIndex overrides and runtime changes// 标记已触发和正在触发fired = firing = true;// 循环调用list中的回调函数// 循环结束之后 firingIndex赋-1 下一次fire从list的第一个开始 除非firingIndex被修改过// 若设置了memory,add的时候会修改firingIndex并调用fire// queue在fireWith函数内被更新,保存了触发函数的context和参数for ( ; queue.length; firingIndex = -1 ) {memory = queue.shift();while ( ++firingIndex < list.length ) { // Run callback and check for early termination// memory[0]是content memory[1]是参数if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&options.stopOnFalse ) {// Jump to end and forget the data so .add doesn't re-fire// 当前执行函数范围false且options.stopOnFalse==true 直接跳至list尾 终止循环firingIndex = list.length;memory = false;}}}// 没设置memory时不保留参数// 设置了memory时 参数仍保留在其中// Forget the data if we're done with itif ( !options.memory ) {memory = false;}firing = false;// Clean up if we're done firing for goodif ( locked ) {// Keep an empty list if we have data for future add callsif ( memory ) {list = [];// Otherwise, this object is spent} else {list = "";}}},
jQuery源码学习之Callbacks相关推荐
- jquery源码学习笔记三:jQuery工厂剖析
jquery源码学习笔记二:jQuery工厂 jquery源码学习笔记一:总体结构 上两篇说过,query的核心是一个jQuery工厂.其代码如下 function( window, noGlobal ...
- jQuery源码学习(1)——addClass
最近比较闲,寻思着学习下jQuery源码,看了好多博客,很多都讲的比较详细.jQuery虽然只有那么200多K,但内容却比较丰富,对于我这样一个js菜鸟,看起来相当吃力.骨头太大,只能化整为零,从简单 ...
- jquery源码学习笔记一:总体结构
练武不练功,到老一场空.计算机也一样. 计算机的功,就是原理.如果程序员只会使用各种函数,各种框架,而不知其原理,顶多熟练工人而已.知其然,更要知其所以然. jquery我们用得很爽,但它究竟咋实现的 ...
- jQuery源码学习
$.jQuery是什么? 平时天天在用的$到底是个什么东西?$("id")思考,感觉像个工厂方法.提供selector创建jquery对象. 一看源码绕晕了,剥茧抽丝吧 定义jqu ...
- jQuery源码学习第二天--jQuery的extend扩展
Jquery中的extend扩展 一.看下常见的extend扩展: 1: jQuery.extend({ 2: noConflict: function( deep ) { 3: if ( windo ...
- jQuery源码学习(6)-Sizzle选择器(2)
1.CSS选择器的位置关系: 四种关系:"+" 紧挨着的兄弟关系:">" 父子关系:" " 祖先关系:"~" 之后 ...
- jQuery源码学习(5)-Sizzle选择器(1)
1.常见的选择器: #test表示id为test的DOM节点 .aaron 表示class为aaron的DOM节点 nav>li 表示在nav内部子li的样式,而不是所有的后代元素,只是往下一层 ...
- 通过jQuery源码学习javascript(三)
序 承接上两篇继续写下去.我尽量把我明白的地方给大家说清楚.有些大家的提问我也有点搞不明白,如果有人能解答,再好不过了. 疑问 第一篇中有位博友提出了以下的问题,我也不太明白,如果有明白的,能否告知一 ...
- jQuery源码学习视频
为什么80%的码农都做不了架构师?>>> http://bbs.miaov.com/forum.php?mod=viewthread&tid=7385&extr ...
最新文章
- Spring踩坑记录
- 数据蒋堂 | 做基础软件要投入很多钱?
- Spring实战3-Spring之旅
- 地址空间和虚拟内存(转载)http://topic.csdn.net/u/20090619/10/4c62a13b-536b-4b0a-af09-2271c6a104e1.html...
- 初步了解Linux创建文件系统命令
- c++ 利用内存映射读取大文件
- MVVM是什么?谈谈你对MVVM的理解?
- a:hover span 隐藏/显示 问题
- ngnix学习(二)ngnix常用命令
- jquery 的模块化
- win10解决IE浏览器安装不上的问题
- 云网融合赋能智慧转型,“天翼云管 ”开启贴身云管家时代
- 实时Linux之PREEMPT_RT篇
- 用c语言实现文本文件中的字符筛选分析(二)
- ANSI、C99、C11 标准区别详解
- 语音识别(ASR)论文优选:SynthASR: Unlocking Synthetic Data for Speech Recognition
- RTL8211F 硬件配置
- win11安装使用安卓子系统WSA
- 如何提高信息流广告的转化率?
- 二、CRUD操作以及配置解析
热门文章
- 北大校友马里千:计算机视觉商用的下一个十年,AI 生成应占有一席之地
- NeurIPS 2019 少样本学习研究亮点全解析
- SAP MM 自定义条件类型出现在采购信息记录的'条件'界面里 ?
- SAP MM ME57界面看到的供应源跟Source List主数据不一致?
- 浅析丨AI安防产品发展现状与趋势分析
- SAP MM 公司间STO里交货单PGI之后自动触发内向交货单功能的实现
- 科大讯飞董事长:AI创业,做平台已没有机会
- 心得丨走过最长的路,就是机器学习过程中的弯路
- chinese_L-12_H-768_A-12的一个坑
- 量化因果涌现表明:宏观可以战胜微观