• JS魔法堂: Native Promise Only源码剖析


    一, 前言                            

       深入学习Promise的朋友应该都看过<深入理解Promise五部曲>这一系列的文章, 以解除回调地狱之外的观点来剖析Promise更多的内涵,确实十分精彩.

       Part 1: The Sync Problem(译文:http://segmentfault.com/blog/kk_470661/1190000000586666)

       Part 2: The Inversion Problem(译文:http://segmentfault.com/blog/kk_470661/1190000000591382)

       Part 3: The Trust Problem(译文:http://segmentfault.com/blog/kk_470661/1190000000593885)

       Part 4: The Extension Problem(译文:http://segmentfault.com/blog/kk_470661/1190000000600268)

       Part 5: The LEGO Problem(译文:http://segmentfault.com/blog/kk_470661/1190000000611040)

       NPO(Native Promise Only)是原文作者polyfill的ES6 Promise, 本文为拜读文章及源码后的笔记,以便日后查阅.

       NPO@github

    二, 整体脉络                          

     对于Promise实现而言, 主要的主体类型就两个-----Promise和Thenable. NPO中通过MakeDef构建Promise的内部状态结构体def, 并且通过def.chain存储Promise子节点P2-1,P2-2到P2-n, 从而形成一颗Promise树. 而Thenable的内部状态结构体def_wrapper则由MakeDefWrapper构建而成.

      Promise树的结构并不稳定, 实际上每个Promise节点仅与状态为pending的子节点关联, 一旦子节点状态发生变化则断开关联.(该部分在 notify() 中实现)

      {Promise} then(success, failure) , 将success和failure事件处理函数与新生成的Promise子节点绑定, 但订阅的是Promise父节点的状态变化事件.

      另外NPO中通过构建一个异步执行请求队列(scheduling_queue),来收集异步执行请求然后對请求作同一处理,并通过门(cycle)来防止重复执行异步请求处理操作.

    三, 源码详解                            

      先看看Promise构造函数, 规定仅能通过new方式来构建Promise实例.

    function Promise(executor) {
                    if (typeof executor != "function") {
                            throw TypeError("Not a function");
                    }
    
                    if (this.__NPO__ !== 0) {
                            throw TypeError("Not a promise");
                    }
    
                    // instance shadowing the inherited "brand"
                    // to signal an already "initialized" promise
                    this.__NPO__ = 1;
    
                    // 内部结构体
                    var def = new MakeDef(this);
    
                    this["then"] = function then(success,failure) {
                            var o = {
                                    success: typeof success == "function" ? success : true,
                                    failure: typeof failure == "function" ? failure : false
                            };
                            // Note: `then(..)` itself can be borrowed to be used against
                            // a different promise constructor for making the chained promise,
                            // by substituting a different `this` binding.
                            o.promise = new this.constructor(function extractChain(resolve,reject) {
                                    if (typeof resolve != "function" || typeof reject != "function") {
                                            throw TypeError("Not a function");
                                    }
    
                                    o.resolve = resolve;
                                    o.reject = reject;
                            });
                            // 构建Promise树
                            def.chain.push(o);
                   // 当前Promise节点状态不为pending时,发起异步执行请求事件处理函数
                            if (def.state !== 0) {
                                    schedule(notify,def);
                            }
    
                            return o.promise;
                    };
                    this["catch"] = function $catch$(failure) {
                            return this.then(void 0,failure);
                    };
    
                    try {
                            // 调用工厂方法
                            executor.call(
                                    void 0,
                                    function publicResolve(msg){
                                            resolve.call(def,msg);
                                    },
                                    function publicReject(msg) {
                                            reject.call(def,msg);
                                    }
                            );
                    }
                    catch (err) {
                            reject.call(def,err);
                    }
            }

       Promise的状态变化放在resolve和reject函数中

     function resolve(msg) {
                    var _then, def_wrapper, self = this;
    
                    // already triggered?
                    if (self.triggered) { return; }
    
                    self.triggered = true;
    
                    // unwrap
                    if (self.def) {
                            self = self.def;
                    }
    
                    try {
                            if (_then = isThenable(msg)) {
                // 构造Thenable的内部状态结构体
                                    def_wrapper = new MakeDefWrapper(self);
                                    _then.call(msg,
                                            function $resolve$(){ resolve.apply(def_wrapper,arguments); },
                                            function $reject$(){ reject.apply(def_wrapper,arguments); }
                                    );
                            }
                            else {
                                    self.msg = msg;
                                    self.state = 1;
                                    if (self.chain.length > 0) {
                                            schedule(notify,self);
                                    }
                            }
                    }
                    catch (err) {
                            reject.call(def_wrapper || (new MakeDefWrapper(self)),err);
                    }
            }
    function reject(msg) {
                    var self = this;
    
                    // already triggered?
                    if (self.triggered) { return; }
    
                    self.triggered = true;
    
                    // unwrap
                    if (self.def) {
                            self = self.def;
                    }
    
                    self.msg = msg;
                    self.state = 2;
                    if (self.chain.length > 0) {
                            schedule(notify,self);
                    }
            } 

      下面看一下我觉得最亮眼的地方异步执行请求队列, 主要由以下几个部分组成

        1. notify, 遍历def.chain中的所有Promise子节点, 最后由于所有Promise子节的状态均变为fulfilled或rejected因此清空def.chain.

        2. notifyIsolated, 被notify所调用, 用于单独调用绑定在每个Promise子节点的success或failure事件处理函数, 并修改Promse子节点的状态.

        3. scheduling_queue, 存放异步执行请求(以链表实现, 對队列首尾操作性能比数组高).

        4. schedule, 向异步执行请求队列添加元素, 并发起异步请求处理操作.

          上述的1和2两点将作为异步执行请求被存放在3中.代码中各部分则通过4来對队列和异步执行请求作操作.

            function notify() {
                    for (var i=0; i<this.chain.length; i++) {
                            notifyIsolated(
                                    this,
                                    (this.state === 1) ? this.chain[i].success : this.chain[i].failure,
                                    this.chain[i]
                            );
                    }
                    this.chain.length = 0;
            }
    
            // NOTE: This is a separate function to isolate
            // the `try..catch` so that other code can be
            // optimized better
            function notifyIsolated(self,cb,chain) {
                    var ret, _then;
                    try {
                            if (cb === false) {
                                    chain.reject(self.msg);
                            }
                            else {
                                    if (cb === true) {
                                            ret = self.msg;
                                    }
                                    else {
                                            ret = cb.call(void 0,self.msg);
                                    }
    
                                    if (ret === chain.promise) {
                                            chain.reject(TypeError("Promise-chain cycle"));
                                    }
                                    else if (_then = isThenable(ret)) {
                                            _then.call(ret,chain.resolve,chain.reject);
                                    }
                                    else {
                                            chain.resolve(ret);
                                    }
                            }
                    }
                    catch (err) {
                            chain.reject(err);
                    }
            }
    scheduling_queue = (function Queue() {
                    var first // 指向队首元素
                      , last  // 指向队尾元素
                      , item;
    
                    function Item(fn,self) {
                            this.fn = fn;
                            this.self = self;
                            this.next = void 0;
                    }
    
                    return {
                            // 元素入队
                            add: function add(fn,self) {
                                    item = new Item(fn,self);
                                    if (last) {
                                            last.next = item;
                                    }
                                    else {
                                            first = item;
                                    }
                                    last = item;
                                    item = void 0;
                            },
                            // 清空队列 
                            drain: function drain() {
                                    var f = first;
                                    first = last = cycle = void 0;
    
                                    // 从队首元素开始遍历所有队列元素
                                    while (f) {
                                            f.fn.call(f.self);
                                            f = f.next;
                                    }
                            }
                    };
            })();
    
            // 安排执行状态变化事件的处理函数
            function schedule(fn,self) {
                    scheduling_queue.add(fn,self);
                    // 防止重复发起异步执行请求
                    if (!cycle) {
                            cycle = timer(scheduling_queue.drain);
                    }
            }

    四, 总结                            

      尊重原创,转载请注明来自: http://www.cnblogs.com/fsjohnhuang/p/4293499.html ^_^肥仔John

  • 相关阅读:
    20155318 《网络攻防》Exp6 信息搜集与漏洞扫描
    20155318 《网络攻防》Exp5 MSF基础应用
    20155318 《网络攻防》Exp4 恶意代码分析
    20155318 《网络攻防》Exp3 免杀原理与实践
    20155318 《网络攻防》Exp2 后门原理与实践
    20155318 Exp1 PC平台逆向破解(5)M
    20155318 第十六周课堂实践——嵌入式基础
    2017-2018-2 20155309 南皓芯 Exp9 Web安全基础
    2017-2018-2 20155309南皓芯 Exp8 WEB基础实践
    2017-2018-2 20155309 南皓芯 Exp7 网络欺诈防范
  • 原文地址:https://www.cnblogs.com/fsjohnhuang/p/4293499.html
Copyright © 2020-2023  润新知