规范里面还有很大一部分是讲解Promise 解决过程的,光看规范,很空洞,前面这些规范已经可以指导我们开始写一个自己的Promise了,Promise 解决过程会在我们后面写到了再详细讲解。
自己写一个Promise我们自己要写一个Promise,肯定需要知道有哪些工作需要做,我们先从Promise的使用来窥探下需要做啥:
新建Promise需要使用new关键字,那他肯定是作为面向对象的方式调用的,Promise是一个类。关于JS的面向对象更详细的解释可以看这篇文章。
我们new Promise(fn)的时候需要传一个函数进去,说明Promise的参数是一个函数
构造函数传进去的fn会收到resolve和reject两个函数,用来表示Promise成功和失败,说明构造函数里面还需要resolve和reject这两个函数,这两个函数的作用是改变Promise的状态。
根据规范,promise有pending,fulfilled,rejected三个状态,初始状态为pending,调用resolve会将其改为fulfilled,调用reject会改为rejected。
promise实例对象建好后可以调用then方法,而且是可以链式调用then方法,说明then是一个实例方法。。简单的说就是then方法也必须返回一个带then方法的对象,可以是this或者新的promise实例。
构造函数为了更好的兼容性,本文就不用ES6了。
// 先定义三个常量表示状态 var PENDING = 'pending'; var FULFILLED = 'fulfilled'; var REJECTED = 'rejected'; function MyPromise(fn) { this.status = PENDING; // 初始状态为pending this.value = null; // 初始化value this.reason = null; // 初始化reason } resolve和reject方法根据规范,resolve方法是将状态改为fulfilled,reject是将状态改为rejected。
// 这两个方法直接写在构造函数里面 function MyPromise(fn) { // ...省略前面代码... // 存一下this,以便resolve和reject里面访问 var that = this; // resolve方法参数是value function resolve(value) { if(that.status === PENDING) { that.status = FULFILLED; that.value = value; } } // reject方法参数是reason function reject(reason) { if(that.status === PENDING) { that.status = REJECTED; that.reason = reason; } } } 调用构造函数参数最后将resolve和reject作为参数调用传进来的参数,记得加上try,如果捕获到错误就reject。
function MyPromise(fn) { // ...省略前面代码... try { fn(resolve, reject); } catch (error) { reject(error); } } then方法根据我们前面的分析,then方法可以链式调用,所以他是实例方法,而且规范中的API是promise.then(onFulfilled, onRejected),我们先把架子搭出来:
MyPromise.prototype.then = function(onFulfilled, onRejected) {}那then方法里面应该干什么呢,其实规范也告诉我们了,先检查onFulfilled和onRejected是不是函数,如果不是函数就忽略他们,所谓“忽略”并不是什么都不干,对于onFulfilled来说“忽略”就是将value原封不动的返回,对于onRejected来说就是返回reason,onRejected因为是错误分支,我们返回reason应该throw一个Error:
MyPromise.prototype.then = function(onFulfilled, onRejected) { // 如果onFulfilled不是函数,给一个默认函数,返回value var realOnFulfilled = onFulfilled; if(typeof realOnFulfilled !== 'function') { realOnFulfilled = function (value) { return value; } } // 如果onRejected不是函数,给一个默认函数,返回reason的Error var realOnRejected = onRejected; if(typeof realOnRejected !== 'function') { realOnRejected = function (reason) { if(reason instanceof Error) { throw reason; } else { throw new Error(reason) } } } }参数检查完后就该干点真正的事情了,想想我们使用Promise的时候,如果promise操作成功了就会调用then里面的onFulfilled,如果他失败了,就会调用onRejected。对应我们的代码就应该检查下promise的status,如果是FULFILLED,就调用onFulfilled,如果是REJECTED,就调用onRejected:
MyPromise.prototype.then = function(onFulfilled, onRejected) { // ...省略前面代码... if(this.status === FULFILLED) { onFulfilled(this.value) } if(this.status === REJECTED) { onRejected(this.reason); } }再想一下,我们新建一个promise的时候可能是直接这样用的:
new Promise(fn).then(onFulfilled, onRejected);