实现promise要在熟练使用的基础上完成,首先要明确几点数组
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(exector) {
exector(this.reslove, this.reject)
}
status = PENDING // promise状态
value = undefined // 成功时的值 then方法须要返回
error = undefined // 失败时的值 then方法须要返回
// 成功时的函数
reslove = value => {
// 修改promise状态
this.status = FULFILLED
this.value = value
}
// 失败时的函数
reject = error => {
// 修改promise状态
this.status = REJECTED
this.error = error
}
then(successCallback, failCallback) {
switch (this.status) {
case FULFILLED:
successCallback(this.value)
break
case REJECTED:
failCallback(this.error)
break
}
}
}
// test
const promise = new MyPromise((reslove, reject) => {
reslove('reslove')
})
promise.then(value => {
console.log(value) // reslove
}, error => {
console.log(error)
})
复制代码
经过上面的代码,咱们成功实现了对promise基础原理。调用promise.then方法能够成功打印出‘reslove’。可是,在then方法的实现中咱们并无对PENDING状态作处理。也就是说,假如咱们进行异步操做,当前的promise是没法处理的。好比:promise
const promise = new MyPromise((reslove, reject) => {
setTimeout(()=> {
reslove('reslove')
},2000)
})
复制代码
那么异步状况如何处理呢?以上面setTimeout为例,reslove是在2秒后执行,在调用then方法2秒内当前promise的状态仍然为PENDING。 两步解决:markdown
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(exector) {
exector(this.reslove, this.reject)
}
status = PENDING // promise状态
value = undefined // 成功时的值 then方法须要返回
error = undefined // 失败时的值 then方法须要返回
successCallback = undefined // 成功回调
failCallback = undefined // 失败回调
// 成功时的函数
reslove = value => {
// 修改promise状态
this.status = FULFILLED
this.value = value
this.successCallback && this.successCallback(this.value)
}
// 失败时的函数
reject = error => {
// 修改promise状态
this.status = REJECTED
this.error = error
this.failCallback && this.failCallback(this.error)
}
then(successCallback, failCallback) {
switch (this.status) {
case FULFILLED:
successCallback(this.value)
break
case REJECTED:
failCallBack(this.error)
break
// 异步状况处理
case PENDING:
this.successCallback = successCallback
this.failCallback = failCallback
break
}
}
}
// test
const promise = new MyPromise((reslove, reject) => {
setTimeout(()=> {
reslove('reslove')
}, 2000)
})
promise.then(value => {
console.log(value) // 2秒后: reslove
}, error => {
console.log(error)
})
复制代码
实现第二版后,问题又来了。咱们平时使用promise时同一个promise下的then方法是能够屡次调用的。咱们将测试代码改成异步
// test
const promise = new MyPromise((reslove, reject) => {
setTimeout(()=> {
reslove('reslove')
}, 2000)
})
promise.then(value => {
console.log('第一次调用then: ', value)
})
promise.then(value => {
console.log('第二次调用then: ', value)
})
// 第二次调用then reslove
复制代码
发现代码只执行了最后一次then方法,打印“第二次调用then: reslove”。这显然是与咱们的预期不相符的函数
要实现屡次调用,咱们须要作的是: 以数组形式暂存多个callback,而且在reslove/reject的时候依次调用测试
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(exector) {
exector(this.reslove, this.reject)
}
status = PENDING // promise状态
value = undefined // 成功时的值 then方法须要返回
error = undefined // 失败时的值 then方法须要返回
// 数组暂存
successCallback = [] // 成功回调
failCallback = [] // 失败回调
// 成功时的函数
reslove = value => {
// 修改promise状态
this.status = FULFILLED
this.value = value
// 依次调用
while(this.successCallback.length) this.successCallback.shift()(this.value)
}
// 失败时的函数
reject = error => {
// 修改promise状态
this.status = REJECTED
this.error = error
// 依次调用
while(this.failCallback.length) this.failCallback.shift()(this.error)
}
then(successCallback, failCallback) {
switch (this.status) {
case FULFILLED:
successCallback(this.value)
break
case REJECTED:
failCallBack(this.error)
break
// 异步状况处理
case PENDING:
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
break
}
}
}
// test
const promise = new MyPromise((reslove, reject) => {
setTimeout(()=> {
reslove('reslove')
}, 2000)
})
promise.then(value => {
console.log('第一次调用then: ', value)
})
promise.then(value => {
console.log('第二次调用then: ', value)
})
promise.then(value => {
console.log('第三次调用then: ', value)
})
// 第一次调用then: reslove
// 第二次调用then: reslove
// 第三次调用then: reslove
复制代码
除了屡次调用外,promise还支持链式调用。而且后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值。优化
这里值得注意的是,咱们须要判断上一个then的返回值是什么类型。若是是普通的值,能够直接调用reslove方法。若是是promise对象,则须要根据promise对象返回的结果来决定调用reslove或者reject。ui
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(exector) {
exector(this.reslove, this.reject)
}
status = PENDING // promise状态
value = undefined // 成功时的值 then方法须要返回
error = undefined // 失败时的值 then方法须要返回
successCallback = [] // 成功回调
failCallback = [] // 失败回调
// 成功时的函数
reslove = value => {
// 修改promise状态
this.status = FULFILLED
this.value = value
while(this.successCallback.length) this.successCallback.shift()(this.value)
}
// 失败时的函数
reject = error => {
// 修改promise状态
this.status = REJECTED
this.error = error
while(this.failCallback.length) this.failCallback.shift()(this.error)
}
then(successCallback, failCallback) {
return new Promise((reslove, reject) => {
switch (this.status) {
case FULFILLED:
reslovePromise(successCallback(this.value), reslove, reject)
break
case REJECTED:
failCallBack(this.error)
break
// 异步状况处理
case PENDING:
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
break
}
})
}
}
// 通用方法 - 解析promise对象 (PENDING、 FULFILLED、REJECTED都会用到)
function reslovePromise(x, reslove, reject) {
if (x instanceof MyPromise) {
x.then(reslove, reject)
} else {
reslove(x)
}
}
// test
const promise = new MyPromise((reslove, reject) => {
reslove('reslove')
})
promise.then(value => {
console.log('第一次调用then: ', value)
return 'reslove2'
}).then(value => {
console.log('第二次调用then: ', value)
return new MyPromise((reslove, reject) => {
reslove('reslove3')
})
}).then(value => {
console.log('第三次调用then: ', value)
})
// 第一次调用then: reslove
// 第二次调用then: reslove2
// 第三次调用then: reslove3
复制代码
到第四版,咱们的MyPromise实现了promise的基本功能。但从代码能够看出,咱们并未对MyPromise作任何错误处理,这并非一段健壮的代码该有的样子。那么接下来,咱们就对MyPromise作一些代码优化及错误处理。this
错误处理想到了两方面。一是在reslove方法执行报错时,将状态改成REJECTED,执行reject方法。二是识别promise返回自对象。spa
const PENDING = 'pending'
const FULFILLED = 'fufilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(exector) {
try {
exector(this.reslove, this.reject)
} catch(e) {
this.reject(e)
}
}
status = PENDING // promise状态
value = undefined // 成功时的值 then方法须要返回
error = undefined // 失败时的值 then方法须要返回
successCallback = [] // 成功回调
failCallback = [] // 失败回调
// 成功时的函数
reslove = value => {
// 修改promise状态
this.status = FULFILLED
this.value = value
while(this.successCallback.length) this.successCallback.shift()()
}
// 失败时的函数
reject = error => {
// 修改promise状态
this.status = REJECTED
this.error = error
while(this.failCallback.length) this.failCallback.shift()()
}
then(successCallback, failCallback) {
// 将then方法的参数变为可选参数
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : error => {throw error}
let newPromise = new MyPromise((reslove, reject) => {
switch (this.status) {
case FULFILLED:
setTimeout(()=> {
try {
reslovePromise(newPromise, successCallback(this.value), reslove, reject)
} catch(e) {
reject(e)
}
}, 0)
break
case REJECTED:
setTimeout(()=> {
try {
reslovePromise(newPromise, failCallback(this.error), reslove, reject)
} catch(e) {
reject(e)
}
}, 0)
break
// 异步状况处理
case PENDING:
this.successCallback.push(()=> {
setTimeout(()=> {
try {
reslovePromise(newPromise, successCallback(this.value), reslove, reject)
} catch(e) {
reject(e)
}
}, 0)
})
this.failCallback.push(()=> {
setTimeout(()=> {
try {
reslovePromise(newPromise, failCallback(this.error), reslove, reject)
} catch(e) {
reject(e)
}
}, 0)
})
break
}
})
return newPromise
}
}
// 通用方法 - 解析promose对象 (PENDING、 FULFILLED、REJECTED都会用到)
function reslovePromise(newPromise ,x, reslove, reject) {
if (newPromise === x) {
return reject(new TypeError('循环调用'))
}
if (x instanceof MyPromise) {
x.then(reslove, reject)
} else {
reslove(x)
}
}
// test
const promise = new MyPromise((reslove, reject) => {
setTimeout(()=> {
reslove('reslove')
}, 2000)
// reject('reject')
})
promise.then(value => {
console.log('第一次调用then reslove: ', value)
throw new Error('then error')
}, error => {
console.log('第一次调用then reject: ', error)
}).then(value => {
console.log('第二次调用then reslove: ', value)
}, error => {
console.log('第二次调用then reject: ', error)
})
// 第一次调用then reslove: reslove
// 第二次调用then reject: Error: then error
复制代码