function MyPromise(fn) {
this.resData // 最終resolve時(shí)的value 或者 最終reject時(shí)的reason
this.onFulfilledList = [] // 當(dāng)resolve之后奸汇,執(zhí)行的內(nèi)部回調(diào)隊(duì)列
this.onRejectedList = [] // 當(dāng)reject之后晓殊,執(zhí)行的內(nèi)部回調(diào)隊(duì)列
this.status = 'pending' // 內(nèi)部的狀態(tài)矮固,只能是pending、fulfilled呆瞻、rejected中的一種,且只能由pending變化為其他兩種,且一旦狀態(tài)改變過柴我,就無(wú)法再進(jìn)行改變
// 第三步:執(zhí)行resolve
// 注:極少數(shù)情況,resolve在then之前調(diào)用扩然,相當(dāng)于Promise對(duì)象狀態(tài)已經(jīng)確定后再去執(zhí)行then注冊(cè)的回調(diào)
const resolve = data => {
// 只有在pending狀態(tài)下才會(huì)繼續(xù)艘儒,保證resolve狀態(tài)不會(huì)被改變
if (this.status != 'pending') return
// 同步代碼,立即修改狀態(tài)為fulfilled,賦值resData界睁,執(zhí)行回調(diào)
this.status = 'fulfilled'
this.resData = data
// 若執(zhí)行此回調(diào)時(shí)觉增,onFulfilledList為空,則相當(dāng)于無(wú)事發(fā)生
if (this.onFulfilledList.length > 0) {
for (let fn of this.onFulfilledList) {
fn(data)
}
}
}
// 第三步:執(zhí)行reject
// 注:極少數(shù)情況翻斟,reject在then之前調(diào)用逾礁,相當(dāng)于Promise對(duì)象狀態(tài)已經(jīng)確定后再去執(zhí)行then注冊(cè)的回調(diào)
const reject = reason => {
// 只有在pending狀態(tài)下才會(huì)繼續(xù),保證reject狀態(tài)不會(huì)被改變
if (this.status != 'pending') return
// 同步代碼访惜,立即修改狀態(tài)為rejected嘹履,賦值resData,執(zhí)行回調(diào)
this.status = 'rejected'
this.resData = reason
// 若執(zhí)行此回調(diào)時(shí)债热,onRejectedList為空植捎,則相當(dāng)于無(wú)事發(fā)生
if (this.onRejectedList.length > 0) {
for (let fn of this.onRejectedList) {
fn(reason)
}
}
}
// 第一步執(zhí)行fn,這里給使用者提供一個(gè)權(quán)力:何時(shí)來resolve或reject
try { // try catch 是為了捕獲錯(cuò)誤
fn(resolve, reject)
} catch (reason) {
reject(reason) // 若捕獲到錯(cuò)誤阳柔,則直接reject
}
}
// 第二步:調(diào)用then來注冊(cè)回調(diào)焰枢,以備原來的Promise對(duì)象的狀態(tài)發(fā)生改變時(shí),執(zhí)行相應(yīng)的回調(diào)方法
// 注:這是最核心的部分
MyPromise.prototype.then = function (onfulfilled, onrejected) {
const self = this
// onfulfilled 和 onrejected 分別對(duì)應(yīng) fulfilled 和 rejected 兩種狀態(tài)的回調(diào)方法
// 參數(shù)若不存在舌剂,則給予默認(rèn)值济锄,此默認(rèn)值用于實(shí)現(xiàn)Promise的穿透效果
if (typeof onfulfilled !== 'function') onfulfilled = value => value
if (typeof onrejected !== 'function') onrejected = reason => { throw reason }
// 若注冊(cè)回調(diào)時(shí),原來的Promise對(duì)象處于pending狀態(tài)
// 我們把原來的Promise對(duì)象稱為oldP
// 注:這是最復(fù)雜的部分
if (this.status == 'pending') {
// 則return一個(gè)新的Promise對(duì)象霍转,我們稱它為newP
return new MyPromise((resolve, reject) => {
// newP最終會(huì)resolve還是reject荐绝,取決于then注冊(cè)的回調(diào)執(zhí)行后的結(jié)果
// 此時(shí)創(chuàng)建一個(gè)回調(diào)函數(shù),主要目標(biāo)是:當(dāng)oldP完成resolve的時(shí)候避消,執(zhí)行此回調(diào)低滩,并且根據(jù)執(zhí)行結(jié)果改變newP的狀態(tài)
let newOnFulfilled = function (data) {
let res
try { // try catch 是為了捕獲錯(cuò)誤
// 此處執(zhí)行的then注冊(cè)的回調(diào)
res = onfulfilled(data)
} catch (e) {
reject(e) // 若捕獲到錯(cuò)誤,則直接reject
return
}
// 若回調(diào)執(zhí)行的結(jié)果為Promise類型岩喷,我們稱它為3P
if (res instanceof MyPromise) {
// 則3P的狀態(tài)將決定newP的狀態(tài)恕沫,此處實(shí)現(xiàn)了Promise之間的串行等待
// 3P達(dá)到fulfilled狀態(tài)的時(shí)候,會(huì)調(diào)用newP的resolve
// 3P達(dá)到rejected狀態(tài)的時(shí)候纱意,會(huì)調(diào)用newP的reject
res.then(resolve, reject)
} else {
// 若回調(diào)執(zhí)行結(jié)果不為Promise類型婶溯,則以此值作為value,令newP達(dá)到resolve
resolve(res)
}
}
// 將此回調(diào)函數(shù)放入外層Promise的onFulfilledList
self.onFulfilledList.push(newOnFulfilled)
// 大體與上面部分相同
let newOnRejected = function (data) {
let res
try {
res = onrejected(data)
} catch (e) {
reject(e)
return
}
if (res instanceof MyPromise) {
res.then(resolve, reject)
} else {
// 注意此處仍然是newP達(dá)到resolve偷霉,因?yàn)閛ldP達(dá)到reject并不影響新的Promise的狀態(tài)迄委,只有then注冊(cè)的回調(diào)的結(jié)果,才可以影響
resolve(res)
}
}
// 將此回調(diào)函數(shù)放入外層Promise的onRejectedList
self.onRejectedList.push(newOnRejected)
})
// 若注冊(cè)回調(diào)時(shí)类少,Promise對(duì)象處于fulfilled狀態(tài)
} else if (this.status == 'fulfilled') {
// 直接執(zhí)行回調(diào)方法即可
let res = onfulfilled(this.resData)
// 若回調(diào)方法的結(jié)果為Promise對(duì)象叙身,則直接return,即為執(zhí)行then之后得到的新的Promise對(duì)象
// or
// 若回調(diào)方法的結(jié)果不為Promise對(duì)象硫狞,則作為新的Promise對(duì)象的value信轿,且默認(rèn)新的Promise對(duì)象狀態(tài)為fulfilled
return MyPromise.resolve(res)
// 若注冊(cè)回調(diào)時(shí)赞警,Promise對(duì)象處于rejected狀態(tài),大體與上面部分相同
} else if (this.status == 'rejected') {
// 直接執(zhí)行回調(diào)方法即可
let res = onrejected(this.resData)
// 若回調(diào)方法的結(jié)果為Promise對(duì)象虏两,則直接return愧旦,即為執(zhí)行then之后得到的新的Promise對(duì)象
// or
// 若回調(diào)方法的結(jié)果不為Promise對(duì)象,則作為新的Promise對(duì)象的value定罢,且新的Promise對(duì)象狀態(tài)仍然為fulfilled
return MyPromise.resolve(res)
}
}
// catch只是一個(gè)語(yǔ)法糖笤虫,完全可以用then替代
MyPromise.prototype.catch = function (onrejected) {
return this.then(null, onrejected)
}
// 相當(dāng)于Promise.resolve方法,生成一個(gè)狀態(tài)為fulfilled的Promise對(duì)象
MyPromise.resolve = function (data) {
if (data instanceof MyPromise) {
return data
} else {
return new MyPromise(resolve => {
resolve(data)
})
}
}
// 相當(dāng)于Promise.reject方法祖凫,生成一個(gè)狀態(tài)為rejected的Promise對(duì)象
MyPromise.reject = function (data) {
return new MyPromise((undefined, reject) => {
reject(data)
})
}
深刻理解Promise系列(五):一個(gè)更好的Promise實(shí)現(xiàn)
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門榨了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人攘蔽,你說我怎么就攤上這事龙屉。” “怎么了满俗?”我有些...
- 文/不壞的土叔 我叫張陵转捕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我唆垃,道長(zhǎng)五芝,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任降盹,我火速辦了婚禮与柑,結(jié)果婚禮上谤辜,老公的妹妹穿的比我還像新娘蓄坏。我一直安慰自己,他們只是感情好丑念,可當(dāng)我...
- 文/花漫 我一把揭開白布涡戳。 她就那樣靜靜地躺著,像睡著了一般脯倚。 火紅的嫁衣襯著肌膚如雪渔彰。 梳的紋絲不亂的頭發(fā)上嵌屎,一...
- 文/蒼蘭香墨 我猛地睜開眼炒瘸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼淤堵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起顷扩,我...
- 序言:老撾萬(wàn)榮一對(duì)情侶失蹤拐邪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后隘截,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扎阶,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年婶芭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乘陪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
- 正文 年R本政府宣布,位于F島的核電站仇穗,受9級(jí)特大地震影響流部,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜纹坐,卻給世界環(huán)境...
- 文/蒙蒙 一枝冀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耘子,春花似錦果漾、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捍歪,卻和暖如春户辱,著一層夾襖步出監(jiān)牢的瞬間鸵钝,已是汗流浹背。 一陣腳步聲響...
- 正文 我出身青樓必逆,卻偏偏與公主長(zhǎng)得像痕届,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子末患,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 題帕三絕 眼空蓄淚淚空垂申屹,暗灑閑拋卻為誰(shuí)。 尺幅鮫綃勞解贈(zèng)隧膏,叫人焉得不傷悲哗讥。 拋珠滾玉只偷潸,鎮(zhèn)日無(wú)心鎮(zhèn)日閑胞枕。 枕...
- 如果我有一百萬(wàn)腐泻,不是五十萬(wàn)决乎,因?yàn)橘I套房子都不夠,也不是一千萬(wàn)派桩,因?yàn)殄X太多要承擔(dān)的責(zé)任和風(fēng)險(xiǎn)也越大构诚,你見過哪個(gè)千萬(wàn)以...
- 爽片中的及格生,好萊塢大片中的差生铆惑。 如果純粹是沖著爽片的觀影期待來看范嘱,我覺得環(huán)太平洋2是基本合格的,但如果抱著好...