代码的本质突出顺序、有序这一概念,尤其在javascript——毕竟javascript是单线程引擎。
javascript拥有函数式编程的特性,而又因为javascript单线程引擎,我们的函数总是需要有序的执行。优秀代码常常 把函数切割成各自的模块,然后在某一特定条件下执行,既然这些函数是有序的执行,那么我们为什么不编写一个统一管理的对象,来帮助我们管理这些函数——于是,Callbacks(回调函数)诞生。
什么是Callbacks
javascript中充斥着函数编程,例如最简单的window.onload承接的就是一个函数,悲催的是window.onload直接赋值的话只能接收一个函数,如果有好几个函数想要在onload中执行,那么我们就需要编写如下代码:
复制代码 代码如下:
function a(elem) {
elem.innerHTML = '我是函数a,我要改变Element的HTML结构';
};
function b(elem) {
elem.innerHTML = '我的函数b,我要改变Element的style';
}
window.onload = function () {
var elem = document.getElementById('test');
a(elem);
b(elem);
};
回调函数初衷就是建立在这么个玩意儿的上面,不再让我们分散这些函数,而是把这些函数统一整理。可以看见,我们在window.onload中希望针对一个Element做两件事情:先改变html结构,然后改变这个html的style。两个函数同样是针对一个Element操作,而这两个函数最终的执行都是有序进行的。那么我们为什么不编写一个这样的对象管理这些函数呢。当然, 这只是回调函数的最基础的存在意义,我们需要的不仅仅是这样一个简单的回调函数对象,我们需要一个更加强大的回调函数。好吧,这只是一个简单的用例,那么我可以告诉你这个回调函数除了一个个执行函数之外,它还可以做什么。
Callbacks本质就是控制函数有序的执行,Javascript是单线程引擎,也就说,javascript同一时间只会有一处代码在运行——即便是Ajax、setTimeout。 这两个函数看起来好像都是异步的,其实并非如此,浏览器在运行javascript代码的时候,这些代码都会被有序的压入一个队列中,当你运行Ajax的时候,浏览器会把Ajax 压入代码队列,浏览器在处理javascript代码是从这个代码队列中一个一个取代码执行的——Callbacks,迎合了这种单线程引擎。
当然,我们要的,不仅仅是这样一个简单的工具对象——在jQuery源码中,Callbacks提供了一组函数的基本管理,为Deferred(异步队列)提供了基础,同时也服务于Queue(同步队列)。 Deferred用于抹平/扁平化金字塔编程(大量的回调函数嵌套,例如Ajax中需要根据请求返回码决定执行的代码); 而Queue,驱动着jQuery.animate(动画引擎)。
那么我们就来编写一个Callbacks吧。
Callbacks模型
Array(数组):
既然我们Callbacks要承接一系列函数,那么必然需要有一个容器。我们可以使用一个数组,并把每一个函数压到该数组中,需要执行的时候,循环数组项执行。
工作模型:
这个Callbacks需要非常的强大,并不仅仅是压入函数,然后执行这么简单,这个Callbacks应该拥有良好的执行模型。
once:当前Callbacks对象中所有的函数只会执行一次,执行一次完之后就会被释放掉,我们可以为使用Callbacks对象的用户提供一个稳定有效的方案,确保函数只会执行一次,之后不再执行,稳定了这些函数的线程。
auto:自动执行模型,这是个有意思的模型,有些函数依赖上一层函数,例如函数b的执行依赖于函数a,那么我们提供一个自动执行的模型:第一次执行这个Callbacks之后,每次添加函数到Callbacks的时候,自动执行过去添加的那些函数,并把最后一次给定的参数数据传递给过去的那些函数,这样就从Callbacks中抹平了这些依赖函数之间需要反复触发的关系,这是个有意思的模型。
once&auto:我们可以让它更强大,同时工作once和auto模型,即:当每次添加函数到Callbacks中的时候,过去的函数都会执行,然后,释放掉这些过去的函数,下次继续添加函数的时候,过去的那些函数不会再执行,因为once模型,已经把它们释放掉了。
API: