JQuery之Callback源码分析

来源:互联网 发布:2017年流行什么网络语? 编辑:程序博客网 时间:2024/05/23 20:11

主要对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使用

0 0
原创粉丝点击