實現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
複製代碼