zoukankan      html  css  js  c++  java
  • Promise 原理探究及其简单实现

    可移步 http://donglegend.com/2016/09/11/promise%E5%8E%9F%E7%90%86%E6%8E%A2%E7%A9%B6/ 观看

    Promise是个什么玩意,大家都知道,度娘告诉我,以同步方式书写异步,解决回调地狱。。。

    状态机

    早闻Promise的大名,简单介绍,根据状态改变来执行相应处理函数。
    Promise的状态极其简单,只有 “pending”, “resolved”, “rejected”三种状态
    然后就是如何实现的问题,最关键的当然是监听到状态的更新,然后才能做出回应,那么如何知道状态变了呢?
    最初单纯的我开了一个脑洞,有以下想法:

    • 写一个定时器不断查询状态值,如果有变化,那么执行回调
    • 利用ES5的 Object.defineProperty(obj, prop, descriptor)来追踪状态变化。
    • 直接修改状态为指定值,然后接着执行回调

    呜呜呜,有时候总会犯傻不是,上面第一种维护一个定时器,效率低下;第二种把状态变得很麻烦和复杂;
    其实很多事情之所以复杂,是因为我们想的太多。
    Promise根本没那么复杂,就三个状态,搞毛线定时器,状态跟踪。
    利用观察者模式,只需要通过特定书写方式注册对应状态的事件处理函数,然后更新状态,调用注册过的处理函数即可。这个特定方式就是 then ,done ,fail, always…等方法;更新状态触发时机就是resolve, reject方法。

    简单实现

    理论分析:

    • 写一个类对象,维护一个 state,值有3种:”pending”, “resolved”, “rejected”
    • 通过then done fail always方法注册回调处理函数
    • 通过resolve reject分别更新对应状态,并且调用注册函数

    代码如下:

     1 /**
     2  * [3种状态]
     3  * @type {String}
     4  */
     5 
     6 var PENDING = "pending";
     7 var RESOLVED = "resolved";
     8 var REJECTED = "rejected";
     9 /**
    10  * [Promise类实现]
    11  * 构造函数传入一个fn,有两个参数,resolve:成功回调; reject:失败回调;
    12  * state: 状态存储
    13  * doneList: 成功处理函数列表
    14  * failList: 失败处理函数列表
    15  * done: 注册成功处理函数
    16  * fail: 注册失败处理函数
    17  * then: 同时注册成功和失败处理函数
    18  * always: 一个处理注册到成功和失败,都会调用
    19  * resolve: 更新state为:RESOLVED,并且执行成功处理队列
    20  * reject: 更新state为:REJECTED,并且执行失败处理队列
    21  */
    22 var Promise = (function (){
    23     function Promise(fn){
    24         this.state = PENDING;
    25         this.doneList = [];
    26         this.failList = [];
    27         this.fn = fn;
    28         this.fn(this.resolve.bind(this), this.reject.bind(this))
    29     }
    30 
    31     var p = {
    32         done: function (cb){
    33             if(typeof cb == "function")
    34                 this.doneList.push(cb)
    35             return this;
    36         },
    37         fail: function(cb){
    38             if(typeof cb == "function")
    39                 this.failList.push(cb);
    40             return this;
    41         },
    42         then: function(success, fail){
    43             this.done(success || noop).fail(fail || noop)
    44             return this;
    45         },
    46         always: function(cb){
    47             this.done(cb).fail(cb)
    48             return this;
    49         },
    50         resolve: function(){
    51             this.state = RESOLVED;
    52             var lists = this.doneList;
    53             for(var i = 0, len = lists.length; i<len; i++){
    54                 lists[0].apply(this, arguments);
    55                 lists.shift();
    56             }
    57             return this;
    58         },
    59         reject: function(){
    60             this.state = REJECTED;
    61             var lists = this.failList;
    62             for(var i = 0, len = lists.length; i<len; i++){
    63                 lists[0].apply(this, arguments);
    64                 lists.shift();
    65             }
    66             return this;
    67         }
    68     }
    69     for(var k in p){
    70         Promise.prototype[k] = p[k]
    71     }
    72 
    73     return Promise;
    74 })();
    75 
    76 function noop(){}

     使用方式,请到https://github.com/donglegend/MyPromise下载使用

    源码下载

  • 相关阅读:
    产品开源了(discuz!nt 2.0),顺便将前些时候发的文章做个总结
    一个曾经的"愤青梦"弥衡
    推荐两个web菜单控件(右击和顶部主菜单)
    一本晚看了两年半的书蓝海战略
    Discuz!NT 在线用户功能简介
    我的2007
    ajax.net调用session和cookie
    最新(2010年)搜索引擎优化(SEO)专家工具集合
    Android学习资料大全
    基于.net的aop实现技术
  • 原文地址:https://www.cnblogs.com/donglegend/p/donglegend.html
Copyright © 2011-2022 走看看