Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

$.Callbacks() 使用 #19

Open
wengjq opened this issue Jan 20, 2018 · 0 comments
Open

$.Callbacks() 使用 #19

wengjq opened this issue Jan 20, 2018 · 0 comments
Labels

Comments

@wengjq
Copy link
Owner

wengjq commented Jan 20, 2018

前言

$.Callbacks 用来管理函数队列。采用了观察者模式,通过 add 添加操作到队列当中,通过 fire 去执行这些操作。实际上 $.Callbacks 是1.7版本从 $.Deferred 对象当中分离出来的,主要是实现 $.Deferred 功能。

API

$.Callbacks

我们通过调用$.Callbacks获取到一个 callback 实例,如下

var cb = $.Callbacks();

看到Callbacks首字母大写,有些人可能会觉得一般只有对象才会这样,因此需要 new 一个实例,如下

var cb = new $.Callbacks();    

实际上这两种方式都可以,因为 Callbacks 函数返回值是一个对象,为什么会这样?看下面一组对比

function Cons() {
    this.name = 'this.name';

    return {
        name: 'obj.name'
    };
}

console.log(Cons().name);//obj.name
console.log(new Cons().name);//obj.name

function Cons() {
    this.name = 'this.name';

    return 'str.name';
}

console.log(Cons());//str.name
console.log(new Cons().name);//this.name

当函数的返回值是一个对象时(null 除外),new 和直接调用两者的返回值是一样的。但是需要注意了,两者的 this 指向是不一样的。为了尽可能的节省代码和避免混乱我们还是统一采用 var cb = $.Callbacks(); 的方式去调用。

像这种先调用获取到实例,然后通过实例进行一系列的操作,很明显利用了闭包特性。

add

向内部队列添加函数,总有三种参数形式

单个函数参数

var cb = $.Callbacks();

cb.add(function () {
    console.log('add one');
});

多个函数参数

var cb = $.Callbacks();

cb.add(function () {
    console.log('add one');
}, function () {
    console.log('add two');
});

数组参数

var cb = $.Callbacks();

cb.add([
    function () {
        console.log('add one');
    }, function () {
        console.log('add two');
    }
]); 

fire

依次执行队列里的函数

var cb = $.Callbacks();

cb.add([
    function () {
        console.log('add one');
    }, function () {
        console.log('add two');
    }
]);

cb.fire();
//add one
//add two

fire的参数会传递给我们添加的函数,例如

var cb = $.Callbacks();

cb.add(function (name, age) {
    console.log(name, age);
});

cb.fire('Jacky', 26);//Jacky 26

fireWith

fire 调用的时候,我们添加函数当中的 this 指向我们的 Callbacks 实例,例如

var cb = $.Callbacks();

cb.add(function () {
    console.log(this === cb);
});

cb.fire();//true

fireWith就是改变我们添加函数的context,即this指向,例如

var cb = $.Callbacks();

var obj = {
    name: 'objName'
};

cb.add(function (age) {
    console.log(this.name, age);
});

cb.fireWith(obj, [26]);//objName 26

fireWith第一个参数是我们的context,第二个参数是我们需要传递的内容数组,注意了是数组!

empty

清空函数队列

var cb = $.Callbacks();

cb.add(function () {
    console.log('add one');
});

cb.empty();
cb.fire();

has

var cb = $.Callbacks();

function demo() {
    console.log('demo');
}
cb.add(demo);
console.log(cb.has(demo));//true

函数传递的都是引用,千万别出现以下的低级错误

var cb = $.Callbacks();

cb.add(function () {
    console.log('demo');
});
cb.has(function () {
    console.log('demo');
});

remove

从内部队列中移除某些函数

var cb = $.Callbacks();

function demo1() {
    console.log('demo1');
}

function demo2() {
    console.log('demo2');
}

cb.add(demo1, demo2);
cb.remove(demo1, demo2);
cb.fire();

disable

禁用回调列表。这种情况会清空函数队列,禁用核心功能。意味着这个回调管理报废了。

var cb = $.Callbacks();

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

cb.disable();
cb.fire();

disabled

回调管理是否被禁用

var cb = $.Callbacks();

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

cb.disable();
console.log(cb.disabled());//true

lock

锁定回调管理,同disable,唯一的差别会在下面表述

locked

回调管理是否被锁

fired

回调队列是否执行过

var cb = $.Callbacks();

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

cb.fire();//add
console.log(cb.fired());//true

$.Callbacks()

$.Callbacks通过字符串参数的形式支持4种及以上的特定功能。很明显的一个工厂模式。

once

函数队列只执行一次。参考以下对比

//不添加参数 
var cb = $.Callbacks();

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

cb.fire();//add
cb.fire();//add

//添加参数
var cb = $.Callbacks('once');

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

cb.fire();//add
cb.fire();

函数队列执行过以后,就不会在执行了,无论调用fire多少次。

unique

往内部队列添加的函数保持唯一,不能重复添加。参考以下对比

//不添加参数
var cb = $.Callbacks();

function demo() {
    console.log('demo');
}
cb.add(demo, demo);

cb.fire();
//demo
//demo

//添加参数
var cb = $.Callbacks('unique');

function demo() {
    console.log('demo');
}
cb.add(demo, demo);

cb.fire();//demo

相同的函数不会被重复添加到内部队列中

stopOnFalse

内部队列里的函数是依次执行的,当某个函数的返回值是false时,停止继续执行剩下的函数。参考以下对比

//不添加参数
var cb = $.Callbacks();

cb.add([
    function () {
        console.log('add one');
    },
    function () {
        console.log('add two');
    }
]);

cb.fire();
//add one
//add two

//添加参数
var cb = $.Callbacks('stopOnFalse');

cb.add([
    function () {
        console.log('add one');
        return false;
    },
    function () {
        console.log('add two');
    }
]);

cb.fire();//add one

注意了返回值一定要是false,像undefined、null这种作为返回值是没有效果的

memory

当函数队列fire或fireWith一次过后,内部会记录当前fire或fireWith的参数。当下次调用add的时候,会把记录的参数传递给新添加的函数并立即执行这个新添加的函数。看个例子

var cb = $.Callbacks('memory');

cb.add(function (name) {
    console.log('one', name);
});

cb.fire('Jacky');//first Jacky

cb.add(function (name) {
    console.log('two', name);
});//two Jacky

例如公司领导在9点的时候发了封邮件,要求大家提交自己的年终终结,这就相当于 fire 操作了,在公司里的员工收到邮件后,立马提交了。小李由于请假,下午才过来,看到邮件后也提交了自己的年终总结。不需要领导再次发送邮件提醒。

fire 或 fireWith 一定要在 disabled 或 lock 前先执行一遍,memory 才会起作用

小结

这四种基本类型可以相互组合起来使用,例如 $.Deferred 就使用了 once 和 memory 的组合。
jQuery.Callbacks("once memory")

disable和lock的区别

两者唯一的区别就是添加了memory参数,看一下对比

var cb = $.Callbacks('memory');

cb.add(function () {
    console.log('one');
});
cb.fire();
cb.disable();
//cb.lock();
cb.add(function () {
    console.log('two');
});

毫无疑问,disable 就是禁用所有功能,无论添加什么参数。而在 memory 的情况下,fire 过后在 lock,继续 add 新的函数依旧会立即执行。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant