手写Promise

按照Promises/A+规范,手写一个Promise
首先第一步:

Promise代码基本结构

先写一个简单的promise调用

const Promise = require('./promise4.js')

function a(){
	return new Promise((resolve,reject)=>{
		let x=1
		resolve(x)
	})
}

a()

接着新建我们的promise4.js文件
每次new出了一个promise实例所以Promise可以是一个类然后导出它

class Promise{
	constructor() {
		
	}
}
module.exports=Promise

然后我们再来完善它,给构造器传入一个函数executor,包含成功和异常的回调。

class Promise{
	constructor(executor) {
		//传入一个executor执行器函数
		const resolve=(value)=>{
			console.log(value);
		}//成功的回调
		const reject=(reason)=>{
			console.log(reason);
		}//异常的回调
	    executor(resolve,reject)
	    //当new出promise实例时此函数立即执行
	}
}
module.exports=Promise

运行下控制台成功返回了成功的回调
在这里插入图片描述

Promise的三种状态及then方法基本结构

接着我们看看promise的三种状态

状态的改变不可逆,一旦状态改变就不能再更改。

  • pending - 进行中
  • fulfilled - 成功
  • rejected - 失败
    在这里插入图片描述
新增状态

所以我们给它新增初始的状态state=‘pending’,并且在执行两个回调里先判断promise状态state是否为pending,是才往下执行。

新增then方法

then方法同样需要两个回调,在判断状态为成功的fulfilled或失败的rejected后执行回调并传入需要的值。

class Promise{
	constructor(executor) {
		//传入一个executor执行器函数,当new出promise实例时立即执行
		this.state='pending'
		this.value='undefined'
		this.reason='undefined'
		//初始化promise的三种状态
		const resolve=(value)=>{
			//对promise状态进行判断
			if(this.state==='pending'){
				this.state='fulfilled'
				this.value=value
			}
		}
		const reject=(reason)=>{
			//对promise状态进行判断
			if(this.state==='pending'){
				this.state='rejected'
				this.reason=reason
			}
		}
	    executor(resolve,reject)
	}
	then(onFulfilled,onRejected){
		if(this.state==='fulfilled'){
			onFulfilled(this.value)
		}
		if(this.state==='rejected'){
			onRejected(this.reason)
		}
	}
}
module.exports=Promise

然后我们测试一下看看:这里打印了成功的回调res参数

const Promise = require('./promise4.js')

function a(){
	return new Promise((resolve,reject)=>{
		let x=1
		resolve(x)
	})
}

a().then(res=>{
	console.log(res);
},err=>{
	console.log(res+'==');
})

执行效果如下:成功返回了1
在这里插入图片描述

让Promise支持异步操作

我们先给promise加上异步操作试试,这里用一个定时器代替效果。

const Promise = require('./promise4.js')

function a(){
	return new Promise((resolve,reject)=>{
		setTimeout(()=>{
			let x=1
			resolve(x)
		},1000)
	})
}

a().then(res=>{
	console.log(res);
},err=>{
	console.log(res+'==');
})

运行以上代码发现控制台并无输出
在这里插入图片描述
这是因为在new一个promise对象后让promise状态改变的resolve和reject函数并没有执行,他需要等待一秒后才会执行,而此时却立即执行了then方法。所以此时的state还是pending状态。所以then里面的代码并不会执行。
在这里插入图片描述
打印出then中此时的state为pending
在这里插入图片描述

异步解决办法

我们这里参照发布订阅者模式,具体思路如下:在执行then方法时先进行判断,如果此时的状态是pending,就把回调函数放到一个数组里,当状态改变时forEach从数组中循环取出执行,新增两个Array类型的数组,用于存放回调函数:
在这里插入图片描述
接着在then中新增pending状态的判断

then(onFulfilled,onRejected){
		// console.log(this.state);
		if(this.state==='fulfilled'){
			onFulfilled(this.value)
		}
		if(this.state==='rejected'){
			onRejected(this.reason)
		}
		//新增判断如果为pending状态则将回调函数依次放入数组中且不执行!
		if(this.state==='pending'){
			this.onResolvedCallbacks.push(()=>{
				onFulfilled(this.value)
			})
			this.onRejectedCallbacks.push(()=>{
				onRejected(this.reason)
			})
		}
	}

接着就是当状态改变时执行我们的回调即可在这里插入图片描述
运行代码现发现在1秒后控制台成功打印出了1,那么我们的promise已经是支持异步操作了。
在这里插入图片描述

链式调用

我们在p1后需要再次.then(需要注意的是p1它return的可能是串字符也可能是个promise)

const Promise = require('./promise4.js')

function a(){
	return new Promise((resolve,reject)=>{
		setTimeout(()=>{
			let x=1
			resolve(x)
		},1000)
	})
}

const p1=a().then(res=>{
	console.log(res);
	//return 'hahaha'
	return new Promise((resolve,reject)=>{
		resolve('========')
	})
},err=>{
	console.log(res+'==');
})
//链式操作
const p2=p1.then(res=>{
	console.log(res);
})

所以then方法里需要再次return 一个promise,我们在then里新增promise并return它。

	then(onFulfilled,onRejected){
		// console.log(this.state);
		const p2=new Promise((resolve,reject)=>{
			if(this.state==='fulfilled'){
				onFulfilled(this.value)
			}
			if(this.state==='rejected'){
				onRejected(this.reason)
			}
			//新增判断如果为pending状态则将回调函数依次放入数组中且不执行!
			if(this.state==='pending'){
				this.onResolvedCallbacks.push(()=>{
					onFulfilled(this.value)
				})
				this.onRejectedCallbacks.push(()=>{
					onRejected(this.reason)
				})
			}
		})
		return p2;
	}

因为return的可能是一个promise,所以我们需要做次判断

新增resolvePromise函数

这里新增一个resolvePromise函数对其进行操作。

then(onFulfilled,onRejected){
		// console.log(this.state);
		const p2=new Promise((resolve,reject)=>{
			if(this.state==='fulfilled'){
				const x = onFulfilled(this.value)
				//此时的x可能为字符串数字或promise等,所以我们需要再对它进行一层操作
				resolvePromise(p2,x,resolve,reject)
			}
			if(this.state==='rejected'){
				onRejected(this.reason)
			}
			//新增判断如果为pending状态则将回调函数依次放入数组中且不执行!
			if(this.state==='pending'){
				this.onResolvedCallbacks.push(()=>{
					onFulfilled(this.value)
				})
				this.onRejectedCallbacks.push(()=>{
					onRejected(this.reason)
				})
			}
		})
		return p2;
	}

由于此时的p2还没产生,这里需要一个定时器使其进入下一事件循环。
在这里插入图片描述
同理下面的其他状态判断也需加上同样的代码(完善后的完整代码如下)

then(onFulfilled,onRejected){
		const promise2=new Promise((resolve,reject)=>{
			if(this.state==='fulfilled'){
				setTimeout(()=>{
					const x=onFulfilled(this.value)
					resolvePromise(promise2,x,resolve,reject)
				},0)
			}
			if(this.state==='rejected'){
				setTimeout(()=>{
					const x=onRejected(this.reason)
					resolvePromise(promise2,x,resolve,reject)
				},0)
			}
			if(this.state==='pending'){
				this.onResolvedCallbacks.push(()=>{
					setTimeout(()=>{
						const x=onFulfilled(this.value)
						resolvePromise(promise2,x,resolve,reject)
					},0)
				})
				this.onRejectedCallbacks.push(()=>{
					setTimeout(()=>{
						const x=onRejected(this.reason)
						resolvePromise(promise2,x,resolve,reject)
					},0)
				})
			}
		})
		return promise2
	}
书写resolvePromise函数
const resolvePromise=(promise2,x,resolve,reject)=>{
	//异常排除
	if(promise2===x){
		return reject(new TypeError('循环引用'))
	}
	//x类型排除
	if(typeof x === 'function' || (typeof x === 'object' && x!== null)){
		try{
			const then=x.then
			if(typeof then=== 'function'){//排除.then是个属性,所以此处认定他是promise
				then.call(x,y=>{
					resolve(y)
				},r=>{
					reject(r)
				})
			}
		}catch(error){
			reject(error)
		}
	}else{
		resolve(x)
	}
}

接着运行代码我们p1return的’======'则通过链式调用顺利被输出了。
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值