1.首先定义一个类MyPromise以及声明一些关键的参数类型
MyPromise
这个类里应该包含
属性
status
状态;callbacks
用于存放then、catch传入的方法result
用于保存结果
方法
resolve
成功回调函数reject
错误回调函数
/**
* 定义泛型
*/
type MyPromiseType = InstanceType<typeof MyPromise>
type GetKeyType<T,K extends keyof T> = T[K]
type Resolve = GetKeyType<MyPromiseType, 'resolve'>
type Reject = GetKeyType<MyPromiseType, 'reject'>
class MyPromise {
[key:string]: any
status: 'resolved' | 'rejected' | 'pending' = 'pending'
callbacks: any[] = []
result:any = null
constructor(fn:(_:Resolve,__:Reject) => void) {
/**
* 绑定函数this指向
*/
this.initBind()
/**
* 初始化值
*/
this.initValue()
fn(this.resolve, this.reject)
}
initValue() {
this.status = 'pending'
this.callbacks = []
this.result = null
}
initBind () {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(data:any) {
if (this.status !== 'pending') return
this.status = 'resolved'
this.result = data
try {
}
reject(data:any) {
if (this.status !== 'pending') return
this.status = 'rejected'
this.result = data
}
}
promise状态一旦发生改变,
是不可逆的
,我们需要在resolve、reject这个方法里面添加
if (this.status !== ‘pending’) return防止promise状态发生二次改变
ps:如果对ts有兴趣可以点击下面可链接
2. 实现then
then实现的功能
- 接受
两个回调函数
,一个成功,一个失败 储存回调函数
,在调用resolve
或者reject
方法时再调用对应的函数(及callbacks
里的方法)- 能够
链式调用
,比如new MyPromise.then(callback).catch(callback)
MyPromise.prototype.then = function(success:Function, onRejected:Function) {
if (this.status === 'pending') {
this.callbacks.push({
success,error})
} else if (this.status === 'resolved') {
setTimeout(() => {
success(this.result)
})
} else if (this.status === 'rejected') {
onRejected(this.result)
}
return this
}
实现思路
- 根据状态
status
判断是将方法存起来还是立即调用; - 用
setTimeout
代替微任务,保证能获取到this.result; return this
保证能链式调用;
3. 实现catch
catch实现的功能
- catch接受
一个回调函数
- 当
then中的回调执行错误时
会执行catch的回调
// 实现catch
MyPromise.prototype.catch = function (onRejected:Function) {
//.catch接受一个回调函数
if (this.status === 'pending') {
// 将回调函数放入callbacks数组中
this.callbacks.push({
onRejected })
} else if (this.status === 'rejected') {
setTimeout(() => {
onRejected(this.result)
})
}
}
这两个方法实现了还暂时不能使用,需要在MyPromise这个类
中的对应方法,加入如下代码
resolve(data:any) {
if (this.status !== 'pending') return
this.status = 'resolved'
this.result = data
try {
this.callbacks.forEach(val => {
val.success && val.success(this.result)
})
} catch (error) {
this.callbacks.forEach(val => {
val.onRejected && val.onRejected(error)
})
}
}
reject(data:any) {
if (this.status !== 'pending') return
this.status = 'rejected'
this.result = data
this.callbacks.forEach(val => {
val.onRejected && val.onRejected(this.result)
})
}
实现思路
- 使用new MyPromise这个方法中,用户主动调用resolve时,
检测是否有在then
中存入的方法; - 由于callbacks这个数组不止装了then的方法,执行时我们需要
执行对用的方法
; - then的回调函数中,如果
出现错误代码,就会执行catch的回调函数
;
4. 实现all
all 实现的功能
- 接收一个Promise
数组
; - 当这个数组所有promise都返回resolve,
Rromise.all返回一个resolve
, 返回的是一个数组,这个数组中的值与promise数组一 一对应的; - 或当其中一个promise返回reject,那么Rromise.all立即中断后面的执行,
立即返回reject
MyPromise.all = function(list:any[]) {
return new MyPromise((resolve, reject) => {
const allList = list.filter(val => val instanceof MyPromise)
const resultList:any[] = Array.from({
length: allList.length})
allList.forEach((val, idx) => {
val
.then((result:any) => {
resultList.splice(idx, 1, result)
resultList.filter(item => item).length === allList.length && resolve(resultList)
})
.catch((err:any) => {
reject(err)
})
})
})
}
最后放上完整代码(包括使用示例)
type MyPromiseType = InstanceType<typeof MyPromise>
type GetKeyType<T,K extends keyof T> = T[K]
type Resolve = GetKeyType<MyPromiseType, 'resolve'>
type Reject = GetKeyType<MyPromiseType, 'reject'>
class MyPromise {
[key:string]: any
status: 'resolved' | 'rejected' | 'pending' = 'pending'
callbacks: any[] = []
result:any = null
constructor(fn:(_:Resolve,__:Reject) => void) {
this.initBind()
this.initValue()
fn(this.resolve, this.reject)
}
initValue() {
this.status = 'pending'
this.callbacks = []
this.result = null
}
initBind () {
this.resolve = this.resolve.bind(this)
this.reject = this.reject.bind(this)
}
resolve(data:any) {
if (this.status !== 'pending') return
this.status = 'resolved'
this.result = data
try {
this.callbacks.forEach(val => {
val.success && val.success(this.result)
})
} catch (error) {
this.callbacks.forEach(val => {
val.onRejected && val.onRejected(error)
})
}
}
reject(data:any) {
if (this.status !== 'pending') return
this.status = 'rejected'
this.result = data
this.callbacks.forEach(val => {
val.onRejected && val.onRejected(this.result)
})
}
}
// 实现then
MyPromise.prototype.then = function(success:Function, onRejected:Function) {
if (this.status === 'pending') {
this.callbacks.push({
success,onRejected})
} else if (this.status === 'resolved') {
setTimeout(() => {
success(this.result)
})
} else if (this.status === 'rejected') {
onRejected(this.result)
}
return this
}
// 实现catch
MyPromise.prototype.catch = function (onRejected:Function) {
//.catch接受一个回调函数
if (this.status === 'pending') {
// 将回调函数放入callbacks数组中
this.callbacks.push({
onRejected })
} else if (this.status === 'rejected') {
setTimeout(() => {
onRejected(this.result)
})
}
}
//实现all
// @ts-ignore
MyPromise.all = function(list:any[]) {
return new MyPromise((resolve, reject) => {
const allList = list.filter(val => val instanceof MyPromise)
const resultList:any[] = Array.from({
length: allList.length})
allList.forEach((val, idx) => {
val
.then((result:any) => {
resultList.splice(idx, 1, result)
resultList.filter(item => item).length === allList.length && resolve(resultList)
})
.catch((err:any) => {
reject(err)
})
})
})
}
// new MyPromise((resolve:any, reject:any) => {
// const num = 1
// setTimeout(() => {
// if (num % 2) {
// resolve({msg: "成功"})
// } else {
// reject({msg: "成功"})
// }
// }, 2000);
// }).then(() => {
// throw Error('124')
// }).catch((err:any) => {
// console.log(err);
// })
// const fn1 = () => {
// return test1
// }
// (async() => {
// const result = await fn1()
// console.log(result);
// })()
const v1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve({
msg: "成功1"})
}, 5000);
})
const v2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve({msg: "成功2"})
reject({
msg: "失败2"})
}, 4000);
})
const v3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve({
msg: "成功3"})
}, 1000);
})
// @ts-ignore
MyPromise.all([v1,v2,v3]).then(res => {
console.log(res);
}).catch((err:any) => {
console.log(err);
})