主要对JQuery的Callback部分进行讲解
Callback源代码
var optionsCache = {};
//主要作用是 once memory unique stopOnFalse
//once: 确保回调队列中的回调函数被执行一次 Deferred会用到
//memory:保留上一次执行的值,那怕后续添加一个回调函数,也确保调用上一次记录的值为参数 Deferred会用到
//unique:确保同一个函数仅被添加一次
//stopOnFalse:如果回调函数队列中有一个回调函数执行后返回false就立即中断剩下的回调函数执行
function createOptions(options) {
var object = optionsCache[options] = {};
//core_rnotwhite = /\S+/g,
//var core_rnotwhite = /\S+/g; "one test ".match(core_rnotwhite)
//["one", "test"]
jQuery.each(options.match(core_rnotwhite) || [], function (_, flag) {
object[flag] = true;
});
return object;
}
//主体部分
//比如传入 "once memory"
//optionsCache["once memory"]={},optionsCache["once memory"]["once"]=true,optionsCache["once memory"]["memory"]=true;
jQuery.Callbacks = function (options) {
options = typeof options === "string" ?
(optionsCache[options] || createOptions(options)) :
jQuery.extend({}, options);
var
firing,//标志位,如果队列正在执行 flag to know if list is currently firing
memory,//最后执行的值 last fire value
fired,//标志位,如果队列已经执行 flag to know if list was already fired
firingLength,//执行时,整个队列长度 end of the loop when firing
firingIndex,//回调队列正在执行的当前函数的队列索引 index of currently firing callback
firingStart,//真正执行回调队列中 的回调函数在队列中的起始位置 first callback to fire
list = [],//实际的回调队列 actual callback list
stack = !options.once && [],//栈保存可以多次被执行的队列
//stack : 当"once memory"的时候,stack=false;当"memory"的时候,stack=[];这个主要是针对once来说的
fire = function (data) {
//初始化标志信息
memory = options.memory && data; //&&短操作符,如果碰到false(可以转化为false的)就去那个值,如果没有碰到就去最后一个
fired = true;
firingIndex = firingStart || 0; //||短操作符,如果碰到true(可以转化为true的)就取那个值,取第一个为true的值,否则也是取最后一个
firingStart = 0;
firingLength = list.length;
firing = true;
for (; list && firingIndex < firingLength; firingIndex++) {
//队列中的函数执行,看回调是否阻止当执行的函数返回false的时候,是否停止对后续回调的调用 当有阻止模式时
if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) {
memory = false;
break;
}
}
firing = false;
//执行完回调函数后,对后续队列进行处理,主要是针对几种模式,分别处理
if (list) {
if (stack) {//当栈中有数据时,即是非 once模式时
if (stack.length) {
fire(stack.shift());
}
} else if (memory) {//当有记忆模式时
list = [];
} else { //其他情况
self.disable();
}
}
},
//真实的callback对象
slef = {
//添加一个callback 或者 callback 集合到 回调队列中去
add: function () {
if (list) {
//我们保持当前长度
var start = list.length;
//立即执行第一次调用
(function add(args) {
jQuery.each(args, function (_, arg) {
var type = jQuery.type(arg);//判断arguments数组中单个元素的类型
if (type === "function") {
//当为非唯一模式和队列没有arg回调函数时
if (!options.unique || !self.has(arg)) {
list.push(arg);
}
} else if (arg && arg.length && type !== "string") {//当arg为数组并且不是字符型,即为[]类型
add(arg); //递归添加
}
});
})(arguments);
//针对模式后续处理
if (firing) {
firingLength = list.length;
} else if (memory) { //当有记忆模式时候,后续添加的函数会被立即调用,使用上一次调用的参数
firingStart = start;
fire(memory);
}
}
return list;
},
remove: function () {
if (list) {
jQuery.each(arguments, function (_, arg) {
var index;
//从0检索arg是否在list中
while ((index = jQuery.inArray(arg, list, index)) > -1) {
list.splice(index, 1);
//调整firing的长度和索引
if (firing) {
if (index <= firingLength) {
firingLength--;
}
if (index <= firingIndex) {
firingIndex--;
}
}
}
});
}
return this;
},
//函数是否在回调队列中
has: function (fn) {
return fn ? jQuery.inArray(fn, list) > -1 : !!(list && list.length);
},
//清空队列
empty: function () {
list = [];
firingLength = 0;
return this;
},
//使队列不够做任何事情了,已经undefined了
disable: function () {
list = stack = memory = undefined;
return this;
},
//是否是可用状态
disabled: function () {
return !list;
},
//锁定栈为他的当前状态
lock: function () {
stack = undefined;
if (!memory) {//当为记忆模式时候
self.disable();
}
return this;
},
//栈的当前状态
locked: function () {
return !stack;
},
//调用回调集合并且传递上下文和参数信息过去
fireWith: function (context, args) {
args = args || [];
//args为数组的时候就让其为数组,当不为数组的时候把它变为数组
args = [context, args.slice ? args.slice() : args];
if (list && (!fired || stack)) {
if (firing) {//当正在执行时,把arguments推到栈中去
stack.push(args);
} else {//当为非执行状态的时候,就立马执行调用队列中的回调,并且把回调参数传递进去
// 这里的fire是调用上面的fire,而非下面的fire
//因为fire还在后面定义的
//所以下面的fire是对fireWith不可见的
fire(args);
}
}
return this;
},
//调用回调使用调用给的参数
fire: function () {
slef.fireWith(this, arguments);
return this;
},
//回调是否已经被调用过了
fired: function () {
return !!fired;
}
};
return self;
}
使用方式见
JQuery官方Callback使用