Zepto源码之deferred模块

这个其实就是一种对 Promise/A+ 规范的实现。


;(function($){
  var slice = Array.prototype.slice

  function Deferred(func) {
    // 用于储存状态切换的方法名,与对应的执行方法
    // $.Callback({once:1,memory:1}) 用来表示只执行一次,且立即触发
    var tuples = [
          [ "resolve", "done", $.Callbacks({once:1, memory:1}), "resolved" ],
          [ "reject", "fail", $.Callbacks({once:1, memory:1}), "rejected" ],
          [ "notify", "progress", $.Callbacks({memory:1}) ]
        ],
        // 执行状态,默认为 执行中
        state = "pending",
        promise = {
          // 返回执行状态
          state: function() {
            return state
          },
          // 最后一定要执行的函数,通过调用  deferred.done, deferred.fail 来执行
          always: function() {
            deferred.done(arguments).fail(arguments)
            return this
          },
          then: function() {
            var fns = arguments
            // 其实是返回 deferred 对象上的一个 promise 方法。这样就可以一直链式调用下去,子子孙孙无穷尽也
            return Deferred(function(defer){
              $.each(tuples, function(i, tuple){
                // 判断对应位置的参数是不是一个函数 
                var fn = $.isFunction(fns[i]) && fns[i]
                // deferred[tuple[1]] 对应着 done, fail, process 三个方法,依次执行
                deferred[tuple[1]](function(){
                  // 调用指定回调,并将结果返回到 returned 中
                  var returned = fn && fn.apply(this, arguments)
                  // 如果 returned 是一个 promise ,那么那对应的回调方法传入,并返回 defer.promise()
                  if (returned && $.isFunction(returned.promise)) {
                    returned.promise()
                      .done(defer.resolve)
                      .fail(defer.reject)
                      .progress(defer.notify)
                  } else {
                  // 否则将它修改上下文状态
                    var context = this === promise ? defer.promise() : this,
                        values = fn ? [returned] : arguments
                    defer[tuple[0] + "With"](context, values)
                  }
                })
              })
              fns = null
            }).promise()
          },

          // 返回 promise 对象,如果 obj 上有值,那么将其扩展到 promise 上
          promise: function(obj) {
            return obj != null ? $.extend( obj, promise ) : promise
          }
        },
        deferred = {}

    // 通过遍历 tuples 生成方法
    $.each(tuples, function(i, tuple){
      var list = tuple[2],
          stateString = tuple[3]

      promise[tuple[1]] = list.add

      // 状态切换
      if (stateString) {
        list.add(function(){
          state = stateString
        }, tuples[i^1][2].disable, tuples[2][2].lock)
      }

      deferred[tuple[0]] = function(){
        deferred[tuple[0] + "With"](this === deferred ? promise : this, arguments)
        return this
      }
      deferred[tuple[0] + "With"] = list.fireWith
    })
    // 使用 promise 扩展 deferred, 让其存在 done, fail, process 三个方法
    promise.promise(deferred)
    if (func) func.call(deferred, deferred)
    return deferred
  }

  // 类似于 Promise 对象中的 all 方法
  $.when = function(sub) {
    var resolveValues = slice.call(arguments),
        len = resolveValues.length,
        i = 0,
        remain = len !== 1 || (sub && $.isFunction(sub.promise)) ? len : 0,
        deferred = remain === 1 ? sub : Deferred(),
        progressValues, progressContexts, resolveContexts,
        // 更新回调,在每个 promise 对象执行 resolve, process 时调用
        updateFn = function(i, ctx, val){
          return function(value){
            ctx[i] = this
            val[i] = arguments.length > 1 ? slice.call(arguments) : value
            if (val === progressValues) {
              deferred.notifyWith(ctx, val)
            } else if (!(--remain)) {
              deferred.resolveWith(ctx, val)
            }
          }
        }

    // 依次处理异步队列
    if (len > 1) {
      progressValues = new Array(len)
      progressContexts = new Array(len)
      resolveContexts = new Array(len)
      for ( ; i < len; ++i ) {
        if (resolveValues[i] && $.isFunction(resolveValues[i].promise)) {
          resolveValues[i].promise()
            .done(updateFn(i, resolveContexts, resolveValues))
            .fail(deferred.reject)
            .progress(updateFn(i, progressContexts, progressValues))
        } else {
          --remain
        }
      }
    }
    if (!remain) deferred.resolveWith(resolveContexts, resolveValues)
    return deferred.promise()
  }

  $.Deferred = Deferred
})(Zepto)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值