- 誕生:
- commonJS社區(qū)提出Promise規(guī)范苫纤,用于統(tǒng)一處理異步回調(diào),后被列入ECMAScript2015標準
- 主要特點:
- 本質(zhì)就是Promise類纲缓,用于表示任務最終結(jié)果是成功還是失敗
- 鏈式調(diào)用卷拘,解決大量的回調(diào)嵌套,避免回調(diào)地獄祝高,代碼結(jié)構(gòu)清晰
- 同步與異步回調(diào)均可處理
- 狀態(tài)(state):
- pending(等待栗弟,promise的初始狀態(tài))
- fulfuilled(成功)
- rejected(失敗)
只存在pending-->fulfuilled 或者 pending-->rejected褂策。fulfuilled 與 rejected 只會執(zhí)行一個横腿。
- 手寫實現(xiàn)(參考系統(tǒng)promise):
- 原型對象函數(shù)
- excutor函數(shù)
需要立即執(zhí)行,所以在構(gòu)造函數(shù)中直接調(diào)用 - reslove 與 reject
使用箭頭函數(shù)斤寂,保留this指向 - then函數(shù)
判斷state耿焊,處理同步和異步(異步必須在回調(diào)后才會改變state) - finally函數(shù)
無論promise對象返回成功還是失敗,finally都會被執(zhí)行一次遍搞,并且回調(diào)結(jié)果可以執(zhí)行then函數(shù) - catch函數(shù)
then函數(shù)不執(zhí)行success回調(diào)版本
- excutor函數(shù)
- 靜態(tài)函數(shù)
- all
處理異步并發(fā)罗侯,按照異步代碼調(diào)用順序得到異步代碼執(zhí)行結(jié)果,參數(shù)為數(shù)組溪猿,數(shù)組值的順序即結(jié)果的順序钩杰,返回值也是promise對象 - resolve
對value進行promise包裝,返回值為promise
- all
- 原型對象函數(shù)
// promise的三種狀態(tài)
// pending 任何回調(diào)之前
const PENDING = "pending"
// fulfuilled 成功回調(diào)
const FULFUILLED = "fulfuilled"
// rejected 失敗回調(diào)
const REJECTED = "rejected"
// promise是類對象
class MyPromise {
constructor (excutor) {
// excutor異常處理
try {
// 外部excutor對象诊县,傳入兩個函數(shù)對象讲弄,對應 reslove reject
excutor(this.reslove, this.reject)
} catch (error) {
this.reject(error)
}
}
// 初始化狀態(tài)
status = PENDING
// 存放所有的成功回調(diào)函數(shù)
sucCallBack = []
// 存放所有的失敗回調(diào)函數(shù)
failCallBack = []
value = undefined
reason = undefined
reslove = value => {
// 用于阻止非 pending 的調(diào)用(執(zhí)行 resolve 和 reject 必須二選一)
if (this.status !== PENDING) return
this.status = FULFUILLED
this.value = value
// FIFO
while (this.sucCallBack.length) {
this.sucCallBack.shift()()
}
}
reject = reason => {
// 用于阻止非 pending 的調(diào)用(執(zhí)行 resolve 和 reject 必須二選一)
if (this.status !== PENDING) return
this.status = REJECTED
this.reason = reason
// FIFO
while (this.failCallBack.length) {
this.failCallBack.shift()()
}
}
// 是能被鏈式調(diào)用的,因此then有返回值依痊,是promise
then (sucCallBack, failCallBack) {
// then 參數(shù)變?yōu)榭蛇x
sucCallBack = sucCallBack ? sucCallBack : value => value
failCallBack = failCallBack ? failCallBack : reason => { throw reason }
// 需要返回新的promise避除,用于實現(xiàn)then 鏈式調(diào)用
let newPromise = new MyPromise((resolve, reject) => {
// 分情況討論:同步 和 異步 回調(diào)處理
// 同步
// 調(diào)用then之前,同步status狀態(tài)已發(fā)生變化
if (this.status === FULFUILLED) {
setTimeout(() => {
try {
// 成功回調(diào)函數(shù)
let newValue = sucCallBack(this.value)
resolvePromise(newPromise, newValue, resolve, reject)
} catch (error) {
// 在新promise中處理異常
reject(error)
}
}, 0);
}
else if (this.status === REJECTED) {
setTimeout(() => {
try {
// 失敗回調(diào)函數(shù)
let newValue = failCallBack(this.reason)
resolvePromise(newPromise, newValue, resolve, reject)
} catch (error) {
// 在新promise中處理異常
reject(error)
}
}, 0);
}
// 異步
else
{
// 異步status狀態(tài)未發(fā)生變化胸嘁,先對回調(diào)函數(shù)做保存
this.sucCallBack.push(() => {
setTimeout(() => {
try {
// 成功回調(diào)函數(shù)
let newValue = sucCallBack(this.value)
resolvePromise(newPromise, newValue, resolve, reject)
} catch (error) {
// 在新promise中處理異常
reject(error)
}
}, 0);
})
this.failCallBack.push(() => {
failCallBack
})
}
})
return newPromise
}
// 無論promise對象返回成功還是失敗瓶摆,finally都會被執(zhí)行一次
finally (callback) {
// then 的返回值是promise
// 不管value是promise對象還是普通值,一律返回promise對象性宏,保證異步promise的執(zhí)行順序
return this.then(value => {
return MyPromise.resolve(callback()).then(()=>value)
},reason => {
return MyPromise.resolve(callback()).then(()=>{throw reason})
})
}
// 只調(diào)用失敗
catch (failCallBack) {
return this.then(undefined, failCallBack)
}
// 處理異步并發(fā)群井,按照異步代碼調(diào)用順序得到異步代碼執(zhí)行結(jié)果,參數(shù)為數(shù)組毫胜,數(shù)組值的順序即結(jié)果的順序书斜,返回值也是promise對象
static all(array) {
let result = []
let index = 0
return new MyPromise((resolve, reject)=>{
function addData(key, value) {
result[key] = value
index ++
// 保證所有(同步于異步)結(jié)果都獲取到后诬辈,在resolve
if (index === array.length) {
resolve(result)
}
}
array.forEach((item, index) => {
if (item instanceof MyPromise) {
// promise對象
item.then(value=>addData(index,value),reason=>reject(reason))
}
else
{
// 普通值
addData(index, item)
}
})
})
}
// 對value進行promise包裝,返回值為promise
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(reslove=>{
reslove(value)
})
}
}
function resolvePromise(newPromise, newValue, resolve, reject) {
// 分情況討論:
// 原promise(防止循環(huán)調(diào)用)
if (newPromise === newValue) {
// 在新promise中處理異常
reject("cycle call promise")
}
// MyPromise
if (newValue instanceof MyPromise) {
// 將狀態(tài)傳遞給下一個promise對象
// ?? ---- 實現(xiàn)then鏈式異步順序調(diào)用
// newValue.then(value=>resolve(value),value=>reject(value))
newValue.then(resolve,reject)
}
// 普通值
else
{
// 在新promise中處理成功回調(diào)
resolve(newValue)
}
}
module.exports = MyPromise