jQuery核心功能函数之callback

jQuery内部核心函数callback

$.callback可以通过add添加回调函数,fire执行回调函数。初始化创建callback实例的时候,可以传递三个参数的组合,stopOnfalse表示如果其中一个回调函数的返回值是false,则后续的回调函数不再执行;once表示只执行一次,即add进去的回调函数只会在第一次fire的时候会执行,如果后面再继续调用fire,回调函数不会再执行;memory表示再调用fire函数以后,后面再继续调用add添加函数的时候,该回调函数会立即执行,且之前执行过的回调不会再被执行,以下是代码的完整简易实现,要点以及个人理解都在代码注释里面。

var cb = $.callbacks('stopOnfalse once memory');

cb.add(function(){
    console.log(1)
    return false
}, function(){
    console.log(2)
});

cb.add(function(){
    console.log(5)
});

cb.fire();

cb.add(function(){
    console.log('3')
})

callback之once

var cb = $.callbacks('once');

cb.add(function(){
    console.log(1)
});

cb.fire(); //输出1
cb.fire(); //没有输出

callback之stopOnfalse

var cb = $.callbacks('once');

cb.add(function(){
    console.log(1)
    return false
}, function(){
    console.log(2)
});

cb.fire(); //输出1 

callback之memory

var cb = $.callbacks('stopOnfalse once memory');

cb.add(function(){
    console.log(1)
});

cb.add(function(){
    console.log(5)
});

cb.fire(); //输出1和5

//会立即执行
cb.add(function(){
    console.log(3)
})

以上会分别输出1,5,3

callback完整代码的简易实现

...
callbacks: function(option){
    //回调函数列表 
    var list = [],
    //执行回调函数的下标 默认从第一个开始
        index,
    //手动设置执行回调函数列表的下标    
        start,
    //回调函数列表的长度
        listLength,
    //回调函数是否执行过
        hasRun;
    //当前回调队列策略 参数 once stopOnfalse memory
    option = typeof option === 'string' ? (optionCach[option] || createOptionCach(option)) : {};
    //当传进来的参数、模式不在缓存对象里面时候 需要重新创建
    function createOptionCach(option){
        //将空对象、缓存对象的对象引用给obj 并返回
        var obj = optionCach[option] = {};
        option.split(/\s+/).forEach(function(opt){
            obj[opt] = true;
        });
        return obj;
    }
    //循环执行回调函数列表里面的回调函数
    var fire = function(data){
        index = start || 0;
        hasRun = true;
        for(index; index < list.length; index++){
            //如果回调函数的返回值是false 同时又配置了stopOnfalse的时候就跳出循环
            if(list[index].call(data[0], data[1]) == false && option.stopOnfalse){
                break;
            };
        }
    }
    var self = {
        add:function(){
            var args = Array.prototype.slice.call(arguments);
            //每次添加回调函数的时候 记录当前回调函数列表的长度
            listLength = list.length;
            //循环遍历args将add进来的回调函数全部放到事件列表list
            args.forEach(function(fn){
                //如果传进来的参数是函数对象 则添加到回调函数列表
                if(toString.call(fn) === '[object Function]'){
                    list.push(fn);
                }
            })
            //当配置的memory的同时回调函数还没执行过 则将下次执行回调函数的下标置为当前事件列表的长度 避免执行的时候重复执行
            if(option.memory && hasRun){
                start = listLength;
                self.fire(arguments);
            }

        },
        fireWith:function(context, arg){
            var args = [context, arg];
            //如果是配置了只执行一次 或者还没执行过才执行
            if(!option.once || !hasRun){
                fire(args)
            }

        },
        fire:function(){
            //把当前jQuery实例对象以及传递的参数通过fireWith传递
            self.fireWith(this, arguments);
        }
    }
    //这里返回self以实现链式调用
    return self;
}
感谢您为我的屌丝逆袭之路添砖加瓦!!!