手写一个Promise/A+,完美通过官方872个测试用例 (4)

如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值

// 我们就根据要求加个判断,注意else里面是正常执行流程,需要resolve // 这是个例子,每个realOnFulfilled后面都要这样写 if(this.status === FULFILLED) { var promise2 = new MyPromise(function(resolve, reject) { try { if (typeof onFulfilled !== 'function') { resolve(that.value); } else { realOnFulfilled(that.value); resolve(that.value); } } catch (error) { reject(error); } }); return promise2; }

如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。这个要求其实在我们检测 onRejected 不是函数的时候已经做到了,因为我们默认给的onRejected里面会throw一个Error,所以代码肯定会走到catch里面去。但是我们为了更直观,代码还是跟规范一一对应吧。需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve。改造代码如下:

if(this.status === REJECTED) { var promise2 = new MyPromise(function(resolve, reject) { try { if(typeof onRejected !== 'function') { reject(that.reason); } else { realOnRejected(that.reason); resolve(); } } catch (error) { reject(error); } }); return promise2; }

如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行下面的 Promise 解决过程:[[Resolve]](promise2, x)。这条其实才是规范的第一条,因为他比较麻烦,所以我将它放到了最后。前面我们代码的实现,其实只要onRejected或者onFulfilled成功执行了,我们都要resolve promise2。多了这条,我们还需要对onRejected或者onFulfilled的返回值进行判断,如果有返回值就要进行 Promise 解决过程。我们专门写一个方法来进行Promise 解决过程。前面我们代码的实现,其实只要onRejected或者onFulfilled成功执行了,我们都要resolve promise2,这个过程我们也放到这个方法里面去吧,所以代码变为下面这样,其他地方类似:

if(this.status === FULFILLED) { var promise2 = new MyPromise(function(resolve, reject) { try { if (typeof onFulfilled !== 'function') { resolve(that.value); } else { var x = realOnFulfilled(that.value); resolvePromise(promise2, x, resolve, reject); // 调用Promise 解决过程 } } catch (error) { reject(error); } }); return promise2; } Promise 解决过程

现在我们该来实现resolvePromise方法了,规范中这一部分较长,我就直接把规范作为注释写在代码里面了。

function resolvePromise(promise, x, resolve, reject) { // 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise // 这是为了防止循环引用 if(promise === x) { return reject(new TypeError('The promise and the return value are the same')); } // 如果 x 为 Promise ,则使 promise 接受 x 的状态 if(x instanceof MyPromise) { // 如果 x 处于等待态, promise 需保持为等待态直至 x 被执行或拒绝 if(x.status === PENDING) { x.then(resolve, reject); } else if(x.status === FULFILLED) { // 如果 x 处于执行态,用相同的值执行 promise resolve(x.value); } else if(x.status === REJECTED) { // 如果 x 处于拒绝态,用相同的据因拒绝 promise reject(x.reason); } } // 如果 x 为对象或者函数 else if(typeof x === 'object' || typeof x === 'function') { try { // 把 x.then 赋值给 then var then = x.then; } catch (error) { // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise reject(error); } // 如果 then 是函数 if(typeof then === 'function') { var called = false; // 将 x 作为函数的作用域 this 调用之 // 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise // 名字重名了,我直接用匿名函数了 try { then.call( x, // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y) function(y){ // 如果 resolvePromise 和 rejectPromise 均被调用, // 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 // 实现这条需要前面加一个变量called if(called) return; called = true; resolvePromise(promise, y, resolve, reject); }, // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise function(r){ if(called) return; called = true; reject(r); }); } catch (error) { // 如果调用 then 方法抛出了异常 e: // 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之 if(called) return; // 否则以 e 为据因拒绝 promise reject(error); } } else { // 如果 then 不是函数,以 x 为参数执行 promise resolve(x); } } else { // 如果 x 不为对象或者函数,以 x 为参数执行 promise resolve(x); } } 处理同步任务

到这里我们的Promise/A+基本都实现了,只是还要注意一个点,如果用户给构造函数传的是一个同步函数,里面的resolve和reject会立即执行,比then还执行的早,那then里面注册的回调就没机会运行了,所以要给他们加个setTimeout:

function resolve(value) { // 这里加setTimeout setTimeout(function() { if(that.status === PENDING) { that.status = FULFILLED; that.value = value; that.onFulfilledCallbacks.forEach(callback => { callback(that.value); }); } }, 0); } function reject(reason) { // 这里加setTimeout setTimeout(function() { if(that.status === PENDING) { that.status = REJECTED; that.reason = reason; that.onRejectedCallbacks.forEach(callback => { callback(that.reason); }); } }, 0); } 测试我们的Promise

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpxfj.html