zoukankan      html  css  js  c++  java
  • jquery.Callbacks的实现

    前言

    本人是一个热爱前端的菜鸟,一直喜欢学习js原生,对于jq这种js库,比较喜欢理解他的实现,虽然自己能力有限,水平很低,但是勉勉强强也算是能够懂一点吧,对于jq源码解读系列,博客园里有很多,推荐大神  艾伦的jq系列,在这里,我仅仅是分享一下我对jq里的Callbacks模块的理解与详细介绍一下我自己仿jq实现的一个callback功能。

    功能介绍

    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时立刻执行。

  • 相关阅读:
    flutter canvas 简单绘画直线
    Yapi 部署及遇到的坑
    flutter 时间选择器第三方插件返回时间格式说明
    windows + flutter + vscode 连接其他模拟器
    flutter 配置环境
    flutter 返回键监听
    flutter 自定义主题切换
    flutter Provide 状态管理篇
    flutter 本地存储 (shared_preferences)
    JS做倒计时的例题
  • 原文地址:https://www.cnblogs.com/xujiazheng/p/6111666.html
Copyright © 2011-2022 走看看