1、Promise规范解读
1、如果x和promise 都指向同一个对象,则以typeError为reason 拒绝执行promise。
2、如果x 是Promise对象,则promise采用x当前的状态:
a. 如果x是pending状态,promise必须保持pending状态直到x的状态变为resolved或者rejected。
b. 如果x是resolved状态,用相同的值value执行promise。
c. 如果x是rejected状态,则用相同的原因reason执行promise。
3、如果x是一个对象或者函数:
a. 将promise的then方法指向x.then。
b. 如果x.then属性抛出异常error,则以error为reason来调用reject。
c. 如果then是是一个函数,那么用x为this来调用它,第一个参数为 resolvePromise,第二个参数为rejectPromise
ⅰ. 如果resolvePromise以值y为参数被调用,则运行 [Resolve]。
ⅱ. 如果 rejectPromise 以据因 r 为参数被调用,则用原因r执行promise(reject)。
ⅲ. 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则使用第一次调用并忽略剩下的调用。
ⅳ. 如果then抛出了异常 error
4、如果 resolvePromise 或 rejectPromise 已经被调用,则忽略它。
5、否则用error为reason拒绝promise
d. 如果then不是function,用x为参数执行promise
6、如果x不是一个object或者function,用x为参数执行promise。
2、实现
构造函数修改:
function CutePromise(executor) {// value 记录异步任务成功的执行结果this.value = null;// reason 记录异步任务失败的原因this.reason = null;// status 记录当前状态,初始化是 pendingthis.status = 'pending';// 缓存两个队列,维护 resolved 和 rejected 各自对应的处理函数this.onResolvedQueue = [];this.onRejectedQueue = [];// 把 this 存下来,后面会用到var self = this;// 定义 resolve 函数function resolve(value) {// 如果是 pending 状态,直接返回if (self.status !== 'pending') {return;}// 异步任务成功,把结果赋值给 valueself.value = value;// 当前状态切换为 resolvedself.status = 'resolved';// 批量执行 resolved 队列里的任务self.onResolvedQueue.forEach(resolved => resolved(self.value));}// 定义 reject 函数function reject(reason) {// 如果是 pending 状态,直接返回if (self.status !== 'pending') {return;}// 异步任务失败,把结果赋值给 valueself.reason = reason;// 当前状态切换为 rejectedself.status = 'rejected';// 用 setTimeout 延迟队列任务的执行// 批量执行 rejected 队列里的任务self.onRejectedQueue.forEach(rejected => rejected(self.reason));}// 把 resolve 和 reject 能力赋予执行器try{execute(resolve, reject)}catch(e){reject(e)}}
then方法:
// then 方法接收两个函数作为入参(可选)CutePromise.prototype.then = function(onResolved, onRejected) {// 注意,onResolved 和 onRejected必须是函数;如果不是,我们此处用一个透传来兜底if (typeof onResolved !== 'function') {onResolved = function(x) {return x};}if (typeof onRejected !== 'function') {onRejected = function(e) {throw e};}// 依然是保存 thisvar self = this;// 这个变量用来存返回值 xlet x// resolve态的处理函数function resolveByStatus(resolve, reject) {// 包装成异步任务,确保决议程序在 then 后执行setTimeout(function() {try {// 返回值赋值给 xx = onResolved(self.value);// 进入决议程序resolutionProcedure(promise2, x, resolve, reject);} catch (e) {// 如果onResolved或者onRejected抛出异常error,则promise2必须被rejected,用error做reasonreject(e);}});}// reject态的处理函数function rejectByStatus(resolve, reject) {// 包装成异步任务,确保决议程序在 then 后执行setTimeout(function() {try {// 返回值赋值给 xx = onRejected(self.reason);// 进入决议程序resolutionProcedure(promise2, x, resolve, reject);} catch (e) {reject(e);}});}// 注意,这里我们不能再简单粗暴 return this 了,需要 return 一个符合规范的 Promise 对象var promise2 = new CutePromise(function(resolve, reject) {// 判断状态,分配对应的处理函数if (self.status === 'resolved') {// resolve 处理函数resolveByStatus(resolve, reject);} else if (self.status === 'rejected') {// reject 处理函数rejectByStatus(resolve, reject);} else if (self.status === 'pending') {// 若是 pending ,则将任务推入对应队列self.onResolvedQueue.push(function() {resolveByStatus(resolve, reject);});self.onRejectedQueue.push(function() {rejectByStatus(resolve, reject);});}});// 把包装好的 promise2 return 掉return promise2;};
resolutionProcedure是关键:
function resolutionProcedure(promise2, x, resolve, reject) {// 这里 hasCalled 这个标识,是为了确保 resolve、reject 不要被重复执行let hasCalled;if (x === promise2) {// 决议程序规范:如果 resolve 结果和 promise2相同则reject,这是为了避免死循环return reject(new TypeError('为避免死循环,此处抛错'));} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {// 决议程序规范:如果x是一个对象或者函数,则需要额外处理下try {// 首先是看它有没有 then 方法(是不是 thenable 对象)let then = x.then;// 如果是 thenable 对象,则将promise的then方法指向x.then。if (typeof then === 'function') {// 如果 then 是是一个函数,那么用x为this来调用它,第一个参数为 resolvePromise,第二个参数为rejectPromisethen.call(x, y => {// 如果已经被 resolve/reject 过了,那么直接 returnif (hasCalled) return;hasCalled = true;// 进入决议程序(递归调用自身)resolutionProcedure(promise2, y, resolve, reject);}, err => {// 这里 hascalled 用法和上面意思一样if (hasCalled) return;hasCalled = true;reject(err);});} else {// 如果then不是function,用x为参数执行promiseresolve(x);}} catch (e) {if (hasCalled) return;hasCalled = true;reject(e);}} else {// 如果x不是一个object或者function,用x为参数执行promiseresolve(x);}}
