1.首先定義一個類MyPromise以及聲明一些關鍵的參數類型
MyPromise
這個類裡應該包含
MyPromise
屬性
-
狀态;status
-
用于存放then、catch傳入的方法callbacks
-
用于儲存結果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有興趣可以點選下面可連結
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
- 用
代替微任務,保證能擷取到this.result;setTimeout
-
保證能鍊式調用;return this
3. 實作catch
catch實作的功能
- catch接受
一個回調函數
- 當
會執行catch的回調then中的回調執行錯誤時
// 實作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這個類
中的對應方法,加入如下代碼
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,
, 傳回的是一個數組,這個數組中的值與promise數組一 一對應的;Rromise.all傳回一個resolve
- 或當其中一個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);
})