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, 本文为拜读文章及源码后的笔记,以便日后查阅.
二, 整体脉络
对于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
欢迎添加我的公众号一起深入探讨技术手艺人的那些事!
如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!