欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  web前端

jquery.Callbacks的实现详解

程序员文章站 2022-03-26 08:15:27
...
前言

jQuery.Callbacks是jquery在1.7版本之后加入的,是从1.6版中的_Deferred对象中抽离的,主要用来进行函数队列的add、remove、fire、lock等操作,并提供once、memory、unique、stopOnFalse四个option进行一些特殊的控制。

功能介绍

jq的Callbacks模块主要是为其他模块提供服务的,他就像一个温柔的小女人,在背后默默地付出。Deferred就像一个巨人,在jq中那么的突出,但在内部,他受到Callbacks的服务。

Callbacks的几种状态:

once -- 回调函数只执行一次

unique -- 函数不能重复添加到回调列表中

memory -- 状态记忆,主要用于Deferred中

stopOnFalse -- 遇到return false 终止回调列表继续执行

我自己实现的Callbacks的几个简单的方法

add -- 向对应的回调函数列表添加一个函数

fire -- 触发回调,回调函数列表依次执行函数

has -- 回调函数列表是否存在传入函数

clear -- 清空回调函数列表

整体结构

首先,我们要向得到一个想要的Callbacks模块,需要这样做:

var cb = Callback('memory once') // 得到一个拥有记忆功能并只执行一次的回调模块

由于我们需要基于一定状态来得到不同的实例,我们可以确定,我们需要一个存储状态的对象

var callbackState = {}

我们给Callback函数传入了'memory once',我们怎么记录这两个状态呢,在这里,仿jq来写的一个函数来实现,如下:

var createCallbackState = function (options) {
 var states = options.split(' ')
 var obj = {}
 for (var i = 0; i < states.length; i++) {
  obj[states[i]] = true
 }
 return obj
 }

以上代码,将 'memory once' 变成了 {memory: true, once: true} ,如果状态缓存对象里有这个对象,直接返回,没有的话先创建再返回。

接下来,就是Callback函数的全部代码了,先上代码

var Callback = function (options) {
 
 var state = callbackState[options] //获取状态模式
 if (!state) {
  callbackState[options] = state = createCallbackState(options)
 }
 var list = [], // 回调函数列表
  memory,  // 存储是否为 记忆状态
  has = function (fn) {
  for (var i = 0; i < list.length; i++) {
   if (list[i] === fn) {
   return true
   }
  }
  return false
  },
  add = function () {
  var i = 0,
   args = arguments,
   len = args.length
  for (; i < len; i++) {
   if (state.unique && has(args[i])) { // 如果是unique状态下并回调列表已经拥有该函数,则不添加
   continue
   }
   list.push(args[i])
  }
  },
  fire = function (context, args) {
  var i = 0,
   len = list.length,
   item
  for (; i < len; i++) {
   item = list[i]
   if (item.apply(context,args) === false && state.stopOnFalse) { //如果函数运行返回false,并且是stopOnFalse状态,终止循环
   break;
   }
  }
  }
 
 return {
  add: function () {
  add.apply(null,arguments)
  // 如果memory模式并且已经拥有了memory信息,接着出发函数
  if (state.memory && memory) {
   fire(memory[0], memory[1])
   list = []
  }
  },
  fire: function (context, args) {
  // 如果memory模式,并且list是空,代表触发在添加前,保存memory信息
  if (state.memory && !list.length) {
   memory = [context, args]
   return
  }
  fire(context,args)
  if (state.once) {
   this.clear()
  }
  },
  has: function (fn) {
  return has(fn)
  },
  clear: function () {
  list = []
  }
 }
 
 }

Callback函数执行后,返回一个对象,然后该对象包含了几个简单的功能。

下面我来介绍一下这部分的实现。

首先,如jq一样,我也定义了内部的add, fire, has方法,主要原因是逻辑需要,在返回对象的方法中实现once,memory状态控制,内部的add,fire方法是纯粹的添加和触发函数。

先来看cb.add方法,add方法可以接收多个函数,因此

add.apply(null,arguments)

使用内部的add做添加功能

再往下的一部分的功能是判断这个回调模块是否是memory状态,理解Deferred模块的同学应该知道,该模块是Promise模式,订阅成功或失败状态的回调函数,然后再某一时刻触发他,这个模式便引用了memory状态下的Callback,这个模式有一个奇怪的地方,如果你先发布成功,但是回调列表空空如也,那么程序并不会发布失败,而是等待成功回调函数的加入,一但回调函数加入,立刻执行他。

就是如下代码

// 如果memory模式并且已经拥有了memory信息,立刻触发函数
 if (state.memory && memory) {
 fire(memory[0], memory[1])
 list = []
 }

提示 : ‘如果你先发布成功,但是回调列表空空如也,那么程序并不会发布失败,而是等待成功回调函数的加入,一但回调函数加入,立刻执行他' 的理解如下代码

var cb = Callback('memory') // 得到记忆功能的回调模块
 
cb.fire() // 触发回调队列
 
cb.add(fn) //添加回调函数,自动执行了!
 
function fn () {
 console.log('fn')
}

如果在非memory状态,以上代码无效。需要再次fire才会执行。

经过上述,fire函数也好理解了,fire可接收两个参数,函数上下文,函数参数数组。

与add中memory状态的代码连串起来,以下代码就是fire时memory状态下的操作

// 如果memory模式,并且list是空,代表触发在添加前,保存memory信息
  if (state.memory && !list.length) {
   memory = [context, args]
   return
  }

如果是memory状态,回调列表为空,就保存函数执行上下文和参数数组,等add时立刻执行。

除了上述以外,代码就很简单易懂啦,Callback函数就到这里了,很简单的功能,唯一一点不好理解的就是memory状态。

相关标签: jquery