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下载使用
源码下载