手写Promise

1.我们先写一个理论上可行的版本
代码分析
- 1.我们用
class
把promise
写成一个类 - 2.构造函数参数是一个
func
,我们在内部需要调用resolve
,reject
两个方法 - 3.
class
里面我们要写resolve
,reject
两个方法 - 4.
promise
的三个状态我们static出来当作常量在,在构造函数中加入status
,result
- 5.在
resolve
,reject
方法中加入status
的办法,并将参数result赋值给result
class Commitment {
static PENDING = '待定'
static FULFILED = '成功'
static REJECTED = '拒绝'
constructor(func) {
this.status = Commitment.PENDING
this.result = null
func(this.resolve, this.reject)
}
resolve (result) {
if (this.status === Commitment.PENDING) {
this.status = Commitment.FULFILED
this.result = result
}
}
reject (result) {
if (this.status === Commitment.PENDING) {
this.status = Commitment.REJECTED
this.result = result
}
}
}
测试竟然报错
let commitment = new Commitment((res, rej) => {
res('这次一定')
})
new之后this指针改变,使用bind改变this指针
func(this.resolve.bind(this), this.reject.bind(this))
2.加上then()
then (onFULFILED, onREJECTED) {
if (this.status === Commitment.FULFILED) {
onFULFILED(this.result)
}
if (this.status === Commitment.REJECTED) {
onREJECTED(this.result)
}
}
简单测试通过
let commitment = new Commitment((res, rej) => {
res('这次一定')
})
commitment.then(
result => { console.log(result); },
result => { console.log(result.message); }
)
3.改进一些bug
构造函数调用函数使用try,catch
有的时候在构造的时候也许会报错,promise会直接输出错误信息,所以我们这里
- 要写成
try
,catch
,然后调用reject返回信息 - 这里的
reject
不用bind
,因为是在创建实例前调用的
// func(this.resolve.bind(this), this.reject.bind(this))
try {
func(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
then传入不是函数报错
commitment.then(
undefined,
// result => { console.log(result); },
result => { console.log(result.message); }
)
我们用条件运算符改写then()
then (onFULFILED, onREJECTED) {
onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
if (this.status === Commitment.FULFILED) {
onFULFILED(this.result)
}
if (this.status === Commitment.REJECTED) {
onREJECTED(this.result)
}
}
4.完成promise的异步功能
我们先来测试一下当前的异步结果
console.log('first');
let commitment = new Commitment((res, rej) => {
console.log('second');
res('这次一定')
})
commitment.then(
result => { console.log(result); },
result => { console.log(result.message); }
)
console.log('third');
- 结果显然很不异步
first
second
这次一定
third
在then()方法中使用setTimeout调用方法
then (onFULFILED, onREJECTED) {
onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
if (this.status === Commitment.FULFILED) {
setTimeout(() => {
onFULFILED(this.result)
})
}
if (this.status === Commitment.REJECTED) {
setTimeout(() => {
onREJECTED(this.result)
})
}
}
5.回调保存
测试:如果在promise里面写一个setTimeout?
- 结果我们没有
resolve
输出了
console.log('first');
let commitment = new Commitment((res, rej) => {
console.log('second');
setTimeout(() => {
res('这次一定')
console.log('fourth');
})
})
commitment.then(
result => { console.log(result); },
result => { console.log(result.message); }
)
console.log('third');
- 输入结果
first
second
third
fourth
分析与改进
- 因为
setTimeout
,then
第一次进入的时候,我们的状态是pending所以没有执行函数 - 所以,我在
pending
状态的时候,把回调函数存起来就可以了(之后resolve
的时候再调用回调即可)
if (this.status === Commitment.PENDING) {
this.resolveCallbacks.push(onFULFILED)
this.rejectCallbacks.push(onREJECTED)
}
- 之后改写
resolve
和reject
方法- 注意:这里也要用setTimeout
resolve (result) {
setTimeout(() => {
if (this.status === Commitment.PENDING) {
this.status = Commitment.FULFILED
this.result = result
this.resolveCallbacks.forEach(callback => {
callback(result)
})
}
})
}
6.链式调用
测试:我们连续使用两次then()
let commitment = new Commitment((res, rej) => {
res('这次一定')
})
commitment.then(
result => { console.log(result); },
result => { console.log(result.message); }
).then(
result => { console.log(result); },
result => { console.log(result.message); }
)
报错如下
then中返回一个Commitment对象
then (onFULFILED, onREJECTED) {
return new Commitment((resolve, reject) => {
onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
if (this.status === Commitment.PENDING) {
this.resolveCallbacks.push(onFULFILED)
this.rejectCallbacks.push(onREJECTED)
}
if (this.status === Commitment.FULFILED) {
setTimeout(() => {
onFULFILED(this.result)
})
}
if (this.status === Commitment.REJECTED) {
setTimeout(() => {
onREJECTED(this.result)
})
}
})
}
汇总完整代码
class Commitment {
static PENDING = '待定'
static FULFILED = '成功'
static REJECTED = '拒绝'
constructor(func) {
this.status = Commitment.PENDING
this.result = null
this.resolveCallbacks = []
this.rejectCallbacks = []
// func(this.resolve.bind(this), this.reject.bind(this))
try {
func(this.resolve.bind(this), this.reject.bind(this))
} catch (error) {
this.reject(error)
}
}
resolve (result) {
setTimeout(() => {
if (this.status === Commitment.PENDING) {
this.status = Commitment.FULFILED
this.result = result
this.resolveCallbacks.forEach(callback => {
callback(result)
})
}
})
}
reject (result) {
setTimeout(() => {
if (this.status === Commitment.PENDING) {
this.status = Commitment.REJECTED
this.result = result
this.rejectCallbacks.forEach(callback => {
callback(result)
})
}
});
}
then (onFULFILED, onREJECTED) {
return new Commitment((resolve, reject) => {
onFULFILED = typeof onFULFILED === 'function' ? onFULFILED : () => { }
onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }
if (this.status === Commitment.PENDING) {
this.resolveCallbacks.push(onFULFILED)
this.rejectCallbacks.push(onREJECTED)
}
if (this.status === Commitment.FULFILED) {
setTimeout(() => {
onFULFILED(this.result)
})
}
if (this.status === Commitment.REJECTED) {
setTimeout(() => {
onREJECTED(this.result)
})
}
})
}
}