这是promise使用的一般形式
let promise = new Promise((resolve, rejected) => {
...todo
resolve(something)
})
那么先来编写Promise最基本的类,首先根据PromiseA+规范
有三个状态,
1.pending
1.1 可能会过渡到fulfilled或者rejected两个状态,是用来区分第一次调用Promise
2.fulfilled
如果state已经是fulfilled,则
2.1 不能改变到其他状态
2.2 必须有一个不能被更改的成功返回值
3.rejected
3.1 不能改变到其他状态
3.2 必须有一个不能被更改的错误原因值
那么根据这个,在class外部定义三个状态
const PENDING = 'PENDING'
const RESOLVE = 'RESOLVE'
const REJECTED = 'REJECTED'
接着,在new Promise时会传入一个匿名函数进去,且返回两个参数
new Promise((resolve, rejected) => {})因此,很容易想到可以传入一个executor,且两个参数都为函数
第一版本:
constructor(executor){
this.status = PENDING
let resolve = () => {
}
let rejected = () => {
}
executor(resolve, rejected)
}
那么如果调用过程出现了抛出异常情况呢?
new Promise(() => {throw new Error('Error')})
解决方案:程序就会直接报错,所以要在内部捕获异常,程序就会rejected
根据promiseA+的规范,rejected有两种情况
1.手动rejected
2.抛出异常
try{
executor(resolve, rejected)
}catch(e){
rejected(e)
}
然后再接着考虑,我们会把值传入给resolve,rejected,会传入任意值,然后我们在then里面会去使用,出于
合理性考虑,应该挂载到this身上,按照规范,应该状态不可逆第二版本:
constructor(executor){
this.status = PENDING
this.reason = undefined //失败的原因
this.value = undefined //成功的值
let resolve = value => {
this.value = value
this.status = RESOLVE
}
let rejected = reason => {
this.value = value
this.status = REJECTED
}
}
届时,再去使用,我们自定义的第一版本promise就阔以愉快的运行啦
最终代码
const PENDING = 'PENDING'
const RESOLVE = 'RESOLVE'
const REJECTED = 'REJECTED'
export default class Promise{
constructor(executor){
this.status = PENDING
this.reason = undefined //失败的原因
this.value = undefined //成功的值
//成功函数
let resolve = value => {
if(this.status === PENDING){ //防止调用rejected,又调用resolve
this.value = value
this.status = RESOLVE
}
}
//失败函数
let rejected = reason => {
if(this.status === PENDING){ //同理
this.reason = reason
this.status = REJECTED
}
}
try{
executor(resolve, rejected) //默认就立刻执行
}catch(e){
rejected(e) //如果执行时发生错误,等价于调用失败方法
}
}
}