上一篇文章中,咱们介绍了Promise的基本使用,在这篇文章中,咱们试着本身来写一个Promise,主要是学习Promise的内部机制,学习它的编程思想。javascript
!!!备注:本文写的很差,仅供本身学习之用,具体的实现过程建议看下面的参考文章。因此本文没有发布到博客园首页和其余地方html
咱们来看一个正常的使用:java
var p=new Promise(function(resolve,rejcet){ setTimeout(function(){ if(true){ resolve('success'); }else{ rejcet('failure'); } },1000); }); p.then(function(value){ console.log(value); },function(error){ console.log(error); }); //success
接下来咱们就来实现这么一个Promise.git
先来了解相关的一些术语: es6
解决(fulfill):指一个 promise 成功时进行的一系列操做,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之。
拒绝(reject):指一个 promise 失败时进行的一系列操做。
终值(eventual value):所谓终值,指的是 promise 被解决时传递给解决回调的值,因为 promise 有一次性的特征,所以当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)。
据因(reason):也就是拒绝缘由,指在 promise 被拒绝时传递给拒绝回调的值。github
promise的执行流程如以下:编程
每一个promise后面链一个对象该对象包含onfulfiled,onrejected,子promise三个属性,当父promise 状态改变完毕,执行完相应的onfulfiled/onfulfiled的时候呢,拿到子promise,在等待这个子promise状态改变,再执行相应的onfulfiled/onfulfiled。依次循环直到当前promise没有子promisesegmentfault
将resolve/reject函数和onfulfiled/onrejected放入同一个对象(promise对象)里面,resolve/reject的时候将value设置this.value=xxx。onfulfiled/onrejected执行的时候呢,onfulfiled(this.value)便可。数组
在这里避免头晕,解释一下,onfulfilled和onrejected指的是then里面的两个函数。promise
如图所示,状态只能由pengding-->fulfilled,或者由pending-->rejected这样转变。
只要这两种状况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对Promise
对象添加回调函数,也会当即获得这个结果。这与事件(Event)彻底不一样,事件的特色是,若是你错过了它,再去监听,是得不到结果的。
一、 首先咱们来写好咱们的框架
ES6原生的构建方式为:
// Promise构造函数接收一个executor函数,executor函数执行完同步或异步操做后,调用它的两个参数resolve和reject var promise = new Promise(function(resolve, reject) { /* 若是操做成功,调用resolve并传入value 若是操做失败,调用reject并传入reason */ })
咱们就按照这种方式来搭好框架
function Promise(callback) { var self = this self.status = 'PENDING' // Promise当前的状态 self.data = undefined // Promise的值 self.onResolvedCallback = [] // Promise resolve时的回调函数集 self.onRejectedCallback = [] // Promise reject时的回调函数集 callback(resolve, reject) // 执行executor并传入相应的参数 function resolve(value){ } function rejecte(error){ } } // 添加咱们的then方法 Promise.prototype.then=function(){ }
咱们构造一个Promise函数,并传入一个回调callback,callback里面传入两个函数做为参数,一个是resove,一个是reject。并在Promise的原型上加入咱们的then方法。
二、完善框架里面的内容
框架搭好了,接下来咱们来一点点的完善框架里面的内容,能够这么说,把resolve,reject和then补充完,基本能够说就是把Promise完成了。
咱们先来完善咱们的resolve和rejected:
function Promise(callback) { var self = this self.status = 'PENDING' // Promise当前的状态 self.data = undefined // Promise的值 self.onResolvedCallback = [] // Promise resolve时的回调函数集 self.onRejectedCallback = [] // Promise reject时的回调函数集 callback(resolve, reject) // 执行executor并传入相应的参数 function resolve(value){ if(self.status=='PENDING'){ self.status=='FULFILLED'; self.data=value; // 依次执行成功以后的函数栈 for(var i = 0; i < self.onResolvedCallback.length; i++) { self.onResolvedCallback[i](value) } } } function rejecte(error){ if (self.status === 'PENDING') { self.status = 'REJECTED' self.data = error; // 依次执行失败以后的函数栈 for(var i = 0; i < self.onRejectedCallback.length; i++) { self.onRejectedCallback[i](error) } } } }
若是是penging,则改变相应的状态,并把resolve和reject的值保存子data里面。
接下来咱们实现咱们的then方法:
then方法是Promise的核心,所以这里会花比较大的篇幅去介绍then:
一个promise的then接受两个参数:
promise.then(onFulfilled, onRejected)
onFulfilled
和 onRejected
都是可选参数。
onFulfilled
不是函数,其必须被忽略onRejected
不是函数,其必须被忽略onFulfilled
特性若是 onFulfilled
是函数:
promise
执行结束后其必须被调用,其第一个参数为 promise
的终值,也就是resolve传过来的值promise
执行结束前其不可被调用onRejected
特性若是 onRejected
是函数:
promise
被拒绝执行后其必须被调用,其第一个参数为 promise
的据因,也就是reject传过来的值promise
被拒绝执行前其不可被调用onFulfilled
和 onRejected
只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码指引擎、环境以及 promise 的实施代码)
onFulfilled
和 onRejected
必须被做为函数调用(即没有 this
值,在 严格模式(strict) 中,函数 this
的值为 undefined
;在非严格模式中其为全局对象。)
then
方法能够被同一个 promise
调用屡次
promise
成功执行时,全部 onFulfilled
需按照其注册顺序依次回调promise
被拒绝执行时,全部的 onRejected
需按照其注册顺序依次回调then
方法必须返回一个 promise
对象
promise2 = promise1.then(onFulfilled, onRejected);
onFulfilled
或者 onRejected
返回一个值 x
,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)
onFulfilled
或者 onRejected
抛出一个异常 e
,则 promise2
必须拒绝执行,并返回拒因 e
onFulfilled
不是函数且 promise1
成功执行, promise2
必须成功执行并返回相同的值onRejected
不是函数且 promise1
拒绝执行, promise2
必须拒绝执行并返回相同的据因不论 promise1
被 reject 仍是被 resolve 时 promise2
都会被 resolve,只有出现异常时才会被 rejected。
每一个Promise对象均可以在其上屡次调用then方法,而每次调用then返回的Promise的状态取决于那一次调用then时传入参数的返回值,因此then不能返回this,由于then每次返回的Promise的结果都有可能不一样。
接下来咱们来写咱们的then方法:
Promise.prototype.then = function(onResolved, onRejected) { var self = this var promise2 // 根据标准,若是then的参数不是function,则咱们须要忽略它,此处以以下方式处理 onResolved = typeof onResolved === 'function' ? onResolved : function(value) {} onRejected = typeof onRejected === 'function' ? onRejected : function(reason) {} if (self.status === 'resolved') { // 若是promise1(此处即为this/self)的状态已经肯定而且是resolved,咱们调用onResolved // 由于考虑到有可能throw,因此咱们将其包在try/catch块里 return promise2 = new Promise(function(resolve, reject) { try { var x = onResolved(self.data) if (x instanceof Promise) { // 若是onResolved的返回值是一个Promise对象,直接取它的结果作为promise2的结果 x.then(resolve, reject) } resolve(x) // 不然,以它的返回值作为promise2的结果 } catch (e) { reject(e) // 若是出错,以捕获到的错误作为promise2的结果 } }) } // 此处与前一个if块的逻辑几乎相同,区别在于所调用的是onRejected函数,就再也不作过多解释 if (self.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { try { var x = onRejected(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) } if (self.status === 'pending') { // 若是当前的Promise还处于pending状态,咱们并不能肯定调用onResolved仍是onRejected, // 只能等到Promise的状态肯定后,才能确实如何处理。 // 因此咱们须要把咱们的**两种状况**的处理逻辑作为callback放入promise1(此处即this/self)的回调数组里 // 逻辑自己跟第一个if块内的几乎一致,此处不作过多解释 return promise2 = new Promise(function(resolve, reject) { self.onResolvedCallback.push(function(value) { try { var x = onResolved(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) self.onRejectedCallback.push(function(reason) { try { var x = onRejected(self.data) if (x instanceof Promise) { x.then(resolve, reject) } } catch (e) { reject(e) } }) }) } } // 为了下文方便,咱们顺便实现一个catch方法 Promise.prototype.catch = function(onRejected) { return this.then(null, onRejected) }
完整代码以下:
try { module.exports = Promise } catch (e) {} function Promise(executor) { var self = this self.status = 'pending' self.onResolvedCallback = [] self.onRejectedCallback = [] function resolve(value) { if (value instanceof Promise) { return value.then(resolve, reject) } setTimeout(function() { // 异步执行全部的回调函数 if (self.status === 'pending') { self.status = 'resolved' self.data = value for (var i = 0; i < self.onResolvedCallback.length; i++) { self.onResolvedCallback[i](value) } } }) } function reject(reason) { setTimeout(function() { // 异步执行全部的回调函数 if (self.status === 'pending') { self.status = 'rejected' self.data = reason for (var i = 0; i < self.onRejectedCallback.length; i++) { self.onRejectedCallback[i](reason) } } }) } try { executor(resolve, reject) } catch (reason) { reject(reason) } } function resolvePromise(promise2, x, resolve, reject) { var then var thenCalledOrThrow = false if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise!')) } if (x instanceof Promise) { if (x.status === 'pending') { //because x could resolved by a Promise Object x.then(function(v) { resolvePromise(promise2, v, resolve, reject) }, reject) } else { //but if it is resolved, it will never resolved by a Promise Object but a static value; x.then(resolve, reject) } return } if ((x !== null) && ((typeof x === 'object') || (typeof x === 'function'))) { try { then = x.then //because x.then could be a getter if (typeof then === 'function') { then.call(x, function rs(y) { if (thenCalledOrThrow) return thenCalledOrThrow = true return resolvePromise(promise2, y, resolve, reject) }, function rj(r) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(r) }) } else { resolve(x) } } catch (e) { if (thenCalledOrThrow) return thenCalledOrThrow = true return reject(e) } } else { resolve(x) } } Promise.prototype.then = function(onResolved, onRejected) { var self = this var promise2 onResolved = typeof onResolved === 'function' ? onResolved : function(v) { return v } onRejected = typeof onRejected === 'function' ? onRejected : function(r) { throw r } if (self.status === 'resolved') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 异步执行onResolved try { var x = onResolved(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'rejected') { return promise2 = new Promise(function(resolve, reject) { setTimeout(function() { // 异步执行onRejected try { var x = onRejected(self.data) resolvePromise(promise2, x, resolve, reject) } catch (reason) { reject(reason) } }) }) } if (self.status === 'pending') { // 这里之因此没有异步执行,是由于这些函数必然会被resolve或reject调用,而resolve或reject函数里的内容已经是异步执行,构造函数里的定义 return promise2 = new Promise(function(resolve, reject) { self.onResolvedCallback.push(function(value) { try { var x = onResolved(value) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) self.onRejectedCallback.push(function(reason) { try { var x = onRejected(reason) resolvePromise(promise2, x, resolve, reject) } catch (r) { reject(r) } }) }) } } Promise.prototype.catch = function(onRejected) { return this.then(null, onRejected) } Promise.deferred = Promise.defer = function() { var dfd = {} dfd.promise = new Promise(function(resolve, reject) { dfd.resolve = resolve dfd.reject = reject }) return dfd }
本文没有写好,有点头晕,因此具体的实现过程仍是建议看下面的参考文章。
参考: