手写Promise(三)

then方法的链式调用

要实现then方法的链式调用,首先要明确的一点是,只有then方法返回Promise对象才可以,另外每一个then方法需要将返回值传递给下一个then方法,而返回值分为普通值和promise对象两种情况
在这里插入图片描述
上图红框内的then方法重构如下:

then = (successCallback, failCallback) => {
	// then方法在一定情况下,可以不传递参数,但是可以将返回值依次传递给后面的then方法,直到传递给有回调的then方法
	successCallback = successCallback ? successCallback : value => value;
	failCallback = failCallback ? failCallback : reason => { throw reason };
	
	const promise = new MyPromise((resolve, reject) => {
		if(this.status === FULFILLED) {
			const x = successCallback(this.value);
 			// 判断 x 的类型,是普通值,还是promise对象
			// 如果 x 时普通值,则直接调用resolve返回
			// 如果 x 是promise对象,则调用then方法,获取状态,并根据状态调用相对应的回调函数
			if(x instanceof MyPromise) {
				x.then(resolve, reject)
			} else {
				resolve(x);
			}
		} else if(this.status === REJECTED) {
			const y = failCallback(this.reason);
			resolve(y);
		} else {
			this.successCallback.push(successCallback);
			this.failCallback.push(failCallback);
		}
	});
	return promise;
}

然而,有一种特殊情况,即then方法回调为promise时,这个promise不能为当前这个promise,如果是当前的promise就会出现死循环式的调用,为避免此类情况,代码修改如下

then = (successCallback, failCallback) => {
	successCallback = successCallback ? successCallback : value => value;
	failCallback = failCallback ? failCallback : reason => { throw reason };
	const promise = new MyPromise((resolve, reject) => {
		if(this.status === FULFILLED) {
			const x = successCallback(this.value);
 			// 判断 x 的类型,是普通值,还是promise对象
			// 如果 x 时普通值,则直接调用resolve返回
			// 如果 x 是promise对象,则调用then方法,获取状态,并根据状态调用相对应的回调函数
			if (promise === x) { // 判断当前的x是否为本身的promise
				return reject(new TypeError('Chaining circle detected for promise #<Promise>'));
			}
			if(x instanceof MyPromise) {
				x.then(resolve, reject)
			} else {
				resolve(x);
			}
		} else if(this.status === REJECTED) {
			const y = failCallback(this.reason);
			resolve(y);
		} else {
			this.successCallback.push(successCallback);
			this.failCallback.push(failCallback);
		}
	});
	return promise;
}

此处代码需要注意的是在promise里面,同步代码是不能获取到还没有声明完成的promise的,
在这里插入图片描述

所以需要将代码改为异步(使用setTimeout包裹代码),代码才能够获取到:

then = (successCallback, failCallback) => {
	successCallback = successCallback ? successCallback : value => value;
	failCallback = failCallback ? failCallback : reason => { throw reason };
	const promise = new MyPromise((resolve, reject) => {
		if(this.status === FULFILLED) {
			setTimeout(() => {
				const x = successCallback(this.value);
	 			// 判断 x 的类型,是普通值,还是promise对象
				// 如果 x 时普通值,则直接调用resolve返回
				// 如果 x 是promise对象,则调用then方法,获取状态,并根据状态调用相对应的回调函数
				if (promise === x) { // 判断当前的x是否为本身的promise
					return reject(new TypeError('Chaining circle detected for promise #<Promise>'));
				}
				if(x instanceof MyPromise) {
					x.then(resolve, reject)
				} else {
					resolve(x);
				}
			}, 0);
		} else if(this.status === REJECTED) {
			const y = failCallback(this.reason);
			resolve(y);
		} else {
			this.successCallback.push(successCallback);
			this.failCallback.push(failCallback);
		}
	});
	return promise;
}

当前代码,只处理了then方法中成功回调的情况,在失败回调和异步模块也需要同样的处理方法,简化代码,需要将公共部分提取成一个公共方法,如下

function resolvePromise(promise, x, resolve, reject) {
	if (promise === x) return reject(new TypeError('Chaining circle detected for promise #<Promise>'));
	if(x instanceof MyPromise) {
		x.then(resolve, reject)
	} else {
		resolve(x);
	}
}

进一步改造then方法如下

then = (successCallback, failCallback) => {
	successCallback = successCallback ? successCallback : value => value;
	failCallback = failCallback ? failCallback : reason => { throw reason };
	const promise = new MyPromise((resolve, reject) => {
		if(this.status === FULFILLED) {
			setTimeout(() => {
				const x = successCallback(this.value);
				resolvePromise(promise, x, resolve, reject);
			}, 0);
		} else if (this.status === REJECTED) {
			setTimeout(() => {
				const x = failCallback(this.reason);
				resolvePromise(promise, x, resolve, reject);
			}, 0);
		} else {
			this.successCallback.push(() => {
				setTimeout(() => {
					const x = successCallback(this.value);
					resolvePromise(promise, x, resolve, reject);
				}, 0);
			});
			this.failCallback.push(() => {
				setTimeout(() => {
					const x = failCallback(this.reason);
					resolvePromise(promise, x, resolve, reject);
				}, 0);
			});
		}
	});
}

又因为then方法中处理异步的部分,返回值处理好了,所以在resolve和reject方法中,调用的时候,就不需要进行传值操作,改动如下

resolve = value => {
	if (this.status !== PENDING) return;
	this.status = FULFILLED;
	this.value = value;
	// while(this.successCallback.length) this.successCallback.shift()(this.value); 
	while(this.successCallback.length) this.successCallback.shift()();  
} 

reject = reason => {
	if (this.status !== PENDING) return;
	this.status = REJECTED;
	this.reason = reason;
	// while (this.failCallback.length) this.failCallback.shift()(this.reason);
	while (this.failCallback.length) this.failCallback.shift()(this.reason);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值