Skip to content

02回调的灵活运用

我们经常会这样使用函数回调:

☑ 事件触发通知 ☑ 资源加载通知 ☑ 定时器延时 ☑ ajax、动画通知等等。

以上都是很单一的事件监听回调的处理方式,但是jQuery把回调函数的用法设计成一个更高的抽像,用于解耦与分离变化。 如何理解这个设计?我们看下面的例子。

例一:

jQuery针对DOM的处理提供了append、prepend、before、after等方法处理,这几个方法的特征:

  1. 参数的传递可以是HTML字符串、DOM元素、元素数组或者jQuery对象
  2. 为了优化性能针对节点的处理需要生成文档碎片

高层接口:

<script> before: function() { return this.domManip(arguments, function(elem) { if (this.parentNode) { this.parentNode.insertBefore(elem, this); } }); }

after: function() { return this.domManip(arguments, function(elem) { if (this.parentNode) { this.parentNode.insertBefore(elem, this.nextSibling); } }) } </script>

底层实现:

<script> domManip: function(args, callback) { // Flatten any nested arrays args = concat.apply([], args); // We can't cloneNode fragments that contain checked, in WebKit if (isFunction) { //多参数处理 self.domManip(args, callback); }

if (l) {
    //生成文档碎片
    fragment = jQuery.buildFragment(args, this[0].ownerDocument, false, this);
    callback.call(this[i], node, i);
}
return this;

} </script>

我们观察下jQuery的实现,通过抽象出一个domManip方法,然后在这个方法中处理共性,合并多个参数的处理与生成文档碎片的处理,然后最终把结果通过回调函数返回给每一个调用者

例二:

在很多时候需要控制一系列的函数顺序执行,那么一般就需要一个队列函数来处理这个问题

<script> function fri(list, callback) { setTimeout(function() { var task;

if (task = list.shift()) {
  task(); // 执行函数
}

if (list.length > 0) {
  arguments.callee(list);  // 递归分解
} else {
  callback();
}

}, 25); }

// 调用 fri([ function() { alert('a') }, function() { alert('b') }, function() { alert('c') }, ], function() { alert('callback') })

// 分别弹出 'a' 'b' 'c' 'callback' </script>

传入一组函数参数,靠递归解析,分个执行,其实就是靠setTimeout可以把函数就爱入到队列末尾才执行的原理 这样的写法就有点就事论事了,聚合对象完全是一个整体,无法再次细分出来,所以我们需要一种方案, 用来管理分离每一个独立的对象

我们换成jQuery提供的方式:

<script> var callbacks = $.Callbacks();

callbacks.add(function() { alert('a') }) callbacks.add(function() { alert('b') }) Callbacks.fire(); // 输出结果 'a' 'b' </script>

Callbacks它是一个多用途的回调函数列表对象,提供了一种强大的方法来管理回调函数队列

那么我们使用回调函数,总的来说弱化耦合,让调用者与被调用者分开,调用者不关心谁是被调用者 所有它需知道的只是存在一个具有某种特定原型、某些限制条件的被调用函数

共 20 个模块,1301 篇 Markdown 文档。