首先我们要搞清楚Promise怎么用的,需要做那些事
`
let myPromise = () => {
return new Promise ((resove, reject) => {
myajax({
url: 'xxx',
success: function (res) {
resolve(res)
},
error: function (err) {
reject(err)
}
})
})
}
myPromise.then().then()
`
或者
`
new Promise ((resove, reject) => {
myajax({
url: 'xxx',
success: function (res) {
resolve(res)
},
error: function (err) {
reject(err)
}
}) 异步操作
})
.then()
.then()
`
其实,promise主要是异步操作完成后,再执行指定操作。
new Promise执行指定异步操作
then中获得异步操作结果,并执行指定回调
那么,实例化Promise时需要执行该异步操作,比如发送一个ajax请求
`
myajax({
url: 'xxx',
success: function (res) {
resolve(res)
},
error: function (err) {
reject(err)
}
})
`
那么,第一步可以写
`
class Promise {
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
_resolve (value) {
}
_reject (value) {
}
}
`
其中参数fn一个异步操作,参数_resove是操作成功时用于返回值的回调,reject是操作失败时的回调
_resove执行什么呢? resolve(res)可知,它是有一个参数的,异步操作的结果。在拿到这个异步操作的结果后,需要执行指定回调
`
class Promise {
value = null
cbs = []
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
_resolve (value) {
this.value = value
this.cbs.forEach(cb => cb)
}
_reject (value) {
}
}
`
cbs是异步操作成功后需要展开的下一步操作,那么cbs从哪里来的?
其实是使用者在then中注册的
那么有
`
class Promise {
value = null
cbs = []
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled) {
this.cbs.push(onFulFilled)
}
_resolve (value) {
this.value = value
this.cbs.forEach(cb => cb)
}
_reject (value) {
}
}
`
仔细考虑,会有问题,从文章一开始的promise使用例子来看,如果传入构造函数的不是异步操作,而是同步操作,那么在注册then之前就先执行了resolve,cbs就是空数组了
所以,我们需要确保,不管then在resolve前注册还是在resolve后注册,都可以被执行到。所以需要状态值pending、fulfilled来帮助实现
`
class Promise {
value = null
cbs = []
state='pending'
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled) {
if (this.state === 'pending') {
this.cbs.push(onFulFilled)
} else if (this.state === 'fulfilled'){
onFulFilled(this.value)
}
}
_resolve (value) {
this.state = 'fulfilled'
this.value = value
this.cbs.forEach(cb => cb)
}
_reject (value) {
}
}
`
到这里,大体轮廓完成了。但是promise使用特点是链式调用then, 也就是每一个then执行完成后都会返回一个promise实例给下一个then。这个promis实例可以是当前实例吗?考虑到当前then执行结果要返回给下一个then作为参数,这个写法不行。所以需要新建一个实例,传递给下一个then
`
class Promise {
value = null
cbs = []
state='pending'
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled) {
return new Promise((resolve, reject) => {
if (this.state === 'pending') {
this.cbs.push(onFulFilled)
} else if (this.state === 'fulfilled'){
let res = onFulFilled(this.value)
resolve(res)
}
})
}
_resolve (value) {
this.state = 'fulfilled'
this.value = value
this.cbs.forEach(cb => cb)
}
_reject (value) {
}
}
`
填充好reject
`
class Promise {
value = null
cbs = []
state='pending'
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === 'pending') {
this.cbs.push(onFulFilled)
} else if (this.state === 'fulfilled'){
let ret = onFulFilled(this.value)
resolve(ret)
} else if (this.state === 'rejected') {
let ret = onRejected(this.value)
reject(ret)
}
})
}
_resolve (value) {
this.state = 'fulfilled'
this.value = value
this.cbs.forEach(cb => {
let ret = cb(value)
cb.resolve(ret)
})
}
_reject (err) {
this.state = 'fulfilled'
this.value = err
this.cbs.forEach(cb => {
let ret = cb(value)
cb.reject(ret)
})
}
}
`
下面考虑异常处理问题
对于异常情形,走reject同样路径
因此有
`
class Promise {
value = null
cbs = []
state='pending'
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === 'pending') {
this.cbs.push(onFulFilled)
} else if (this.state === 'fulfilled'){
let ret = onFulFilled(this.value)
resolve(ret)
} else if (this.state === 'rejected') {
let ret = onRejected(this.value)
reject(ret)
}
})
}
_resolve (value) {
this.state = 'fulfilled'
this.value = value
this.cbs.forEach(cb => {
let ret = cb(value)
cb.resolve(ret)
})
}
_reject (err) {
this.state = 'fulfilled'
this.value = err
this.cbs.forEach(cb => {
let ret = cb(value)
cb.reject(ret)
})
}
catch(onError) {
this.then(null, onError)
}
}
`
下一步考虑finally
无论resolve还是reject都要执行finally,那么差不多是 then(func, func),但是我们的then()是返回本次then执行结束生成的一个promise实例,后面的then和前面的then执行结果有依赖关系,而finally则不需要,所以可以
`
class Promise {
value = null
cbs = []
state='pending'
constructor(fn) {
fn(_resolve.bind(this), _reject.bind(this))
}
then (onFulFilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === 'pending') {
this.cbs.push(onFulFilled)
} else if (this.state === 'fulfilled'){
let ret = onFulFilled(this.value)
resolve(ret)
} else if (this.state === 'rejected') {
let ret = onRejected(this.value)
reject(ret)
}
})
}
_resolve (value) {
this.state = 'fulfilled'
this.value = value
this.cbs.forEach(cb => {
let ret = cb(value)
cb.resolve(ret)
})
}
_reject (err) {
this.state = 'fulfilled'
this.value = err
this.cbs.forEach(cb => {
let ret = cb(value)
cb.reject(ret)
})
}
catch(onError) {
this.then(null, onError)
}
finally(onFinal) {
return
}
}
`
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。