zoukankan      html  css  js  c++  java
  • JSDeferred 源码分析

    不经意看到了一个构思非常惊人的异步流程控制库,发出来分享下

    http://cho45.stfuawsc.com/jsdeferred/ 

    关于CommonJS Promises请看另一个异步库 http://www.cnblogs.com/aaronjs/p/3168588.html

    整个代码非常简洁,易用,不过呢是小日本写的东西…

    API手册:

    加载jsdeferred定义延迟对象。为方便起见,我们用Deferred.define()方法把接口导出到全局作用于中

    Deferred.define();

    通过这样做,你就能使用如 next(), loop(), call(), parallel() and wait() 这样的全局函数方法,让我们抒写一些异步的流程

    next(function () {
        alert("Hello!");
        return wait(5);
    }).
    next(function () {
        alert("World!");
    });

    这个流程中,开始会弹出 “Hello”,然后过5秒接着会弹出 “world”

    Deferred.next(function () {
        alert("Hello!");
        return Deferred.wait(5);
    }).
    next(function () {
        alert("World!");
    });

    上面是抒写同上

    个人分析:

    用Deferred.define()方法,无疑污染了全局作用域,入侵性太强了,跟mootools,prototype一样, 不过好处嘛,很明显,简单易用了

    还好JSDeferred也提供了无侵入的写法

    亮源码:

    Deferred.define = function (obj, list) {
        if (!list) list = Deferred.methods;
        if (!obj)  obj = (function getGlobal() {
            return this
        })();
        for (var i = 0; i < list.length; i++) {
            var n = list[i];
            obj[n] = Deferred[n];
        }
        return Deferred;
    };

    可以传入一个对象,用作上下文

    var o = {}; //定义一个对象 
    Deferred.define(o);//把Deferred的方法加持到它上面,让o成为一个Deferred子类。
    o.next(function(){ 
      /* 处理 */
    })

    Deferred.methods = ["parallel", "wait", "next", "call", "loop", "repeat", "chain"];

    next方法

    • next方法是可以进行链式操作,链式的原理很简单就是要返回当前的的this上下文才可以
    • 所以很明显第一个next我们必须要建一个上下文对象提供给后面next引用,其实跟jquery链式一个道理

    根据源码看来Deferred.next其实就是一个静态方法

    Deferred.next = Deferred.next_faster_way_readystatechange 
        || Deferred.next_faster_way_Image 
        || Deferred.next_tick 
        || Deferred.next_default;

    显而易见,next方法是有四种选择优先级,为什么要这样呢?

    • 目的是用于提供了一个JSDeferred实例与实现第一个异步操作。
    • 异步操作在JSDeferred中有许多实现方法,如setTimeout,img.onerror或 script.onreadystatechange ,
    • 它会视浏览器选择最快的异步方式

    我是基于webkit的游览器,所以我们就直接看Deferred.next_faster_way_Image

    // Modern Browsers
        var d = new Deferred();
        var img = new Image();
        var handler = function () {
            d.canceller();
            d.call();
        };
        img.addEventListener("load", handler, false);
        img.addEventListener("error", handler, false);
        d.canceller = function () {
            img.removeEventListener("load", handler, false);
            img.removeEventListener("error", handler, false);
        };
        img.src = "data:image/png," + Math.random();
        if (fun) d.callback.ok = fun;
        return d;

    流程:

    • 创建一个Deferred对象
    • 创建Image对象,实现异步
    • 监听事件
    • if (fun) d.callback.ok = fun;  放置回调处理对象
    • 返回当前deferred对象

    由此可见

    next(fn).next(fn).next(fn)

    其实就是

    第一个 next()    Deferred.next_faster_way_Image () 返回 d
    
    第二个 next()   d.next()

    第二个next(),其实就是实例Deferred类的原型方法了

    具体我们看

    next: function (fun) {
            return this._post("ok", fun)
        },
    _post: function (okng, fun) {
            this._next = new Deferred();
            this._next.callback[okng] = fun;
            return this._next;
        },

    看到_post方法,就有拨开云雾见月明的感觉了

    其实内部会有重新生成一个 Deferred对象挂到父实例的 next上,在绑定回调..

    如此依次循环处理

    所以初始化的时候其实内部就生成了这么一个队列

    image

    _next 上都挂着下一个队列处理

    此时都是在初始化准备好的了,在执行的时候 Image 在成功回调中,我们调用了 d.call();

    执行实例的call方法

    call: function (val) {
            return this._fire("ok", val)
        },
    _fire: function (okng, value) {
            var next = "ok";
            try {
                value = this.callback[okng].call(this, value);
            } catch (e) {
                next = "ng";
                value = e;
                if (Deferred.onerror) Deferred.onerror(e);
            }
            if (Deferred.isDeferred(value)) {
                value._next = this._next;
            } else {
                if (this._next) this._next._fire(next, value);
            }
            return this;
        }
    • 取出当前实例的回调方法,传入参数
    • 返回的value 是否还是一个isDeferred对象
    • 如果没有返回值,继续调用内部的_next上的Deferred实例,依次循环

    总结:

    构思很特别,把每次链式的回调挂到内部的next子属性中,在处理上也保持了一条线的引用关系,而不是常规的用数组的方式存起来

    当然上面仅仅只是同步方法的处理分析,也不是标准的遵循CommonJS Promises规范去抒写的

  • 相关阅读:
    ASE19团队项目 beta阶段 model组 scrum report list
    ASE19团队项目 beta阶段 model组 scrum7 记录
    ASE19团队项目 beta阶段 model组 scrum6 记录
    ASE19团队项目 beta阶段 model组 scrum5 记录
    ASE19团队项目 beta阶段 model组 scrum4 记录
    ASE19团队项目 beta阶段 model组 scrum3 记录
    ASE19团队项目 beta阶段 model组 scrum2 记录
    ASE19团队项目 beta阶段 model组 scrum1 记录
    【ASE模型组】Hint::neural 模型与case study
    【ASE高级软件工程】第二次结对作业
  • 原文地址:https://www.cnblogs.com/aaronjs/p/3247302.html
Copyright © 2011-2022 走看看