排版很不友好,抱歉
/*
* 實(shí)現(xiàn)Promise是根據(jù)Promise規(guī)范來(lái)的:https://promisesaplus.com/
* 規(guī)范很短,所以每句都很重要
* Promise特點(diǎn)
* 1. 狀態(tài)改變后不可再改變(狀態(tài)凝固)
*? ? pending,fullfilled,rejected
*
* 2. then方法(此方法就是最重要的部分)
*? ? 可以鏈?zhǔn)秸{(diào)用
*? ? then方法返回一個(gè)新的promise實(shí)例
*? promise2 = promise.then(f1, f2)
*? ? 當(dāng)promise的狀態(tài)確定的時(shí)候會(huì)執(zhí)行then中的f1或者f2。
*? ? 在f1/f2執(zhí)行之前then就已經(jīng)返回了一個(gè)Promise實(shí)例(promise2)
*? ? promise2的狀態(tài)由f1/f2的返回值確定,以此類推就是鏈?zhǔn)秸{(diào)用
*
* 3. promise創(chuàng)建時(shí)傳入的函數(shù)會(huì)立即執(zhí)行
*/
/*
* 在考慮某些函數(shù)執(zhí)行時(shí)同步還是異步,考慮四種情況,分別會(huì)有什么問(wèn)題
* 假設(shè)new一個(gè)Promise時(shí)傳入的函數(shù)為funA, then中的函數(shù)為funCD
*? 1 funA是同步,funCD為同步
*? 2 funA是同步,funCD為異步 // 為什么最后只能用這種方式
*? 3 funA是異步,funCD為同步
*? 4 funA是異步,funCD為異步
*/
/*
* 問(wèn)題: 1,狀態(tài)是怎么改變的(這是個(gè)好問(wèn)題,是面試官提的。當(dāng)時(shí)我真的沒(méi)答出來(lái))
*? ? ? ? ? 在執(zhí)行resolve,reject函數(shù)時(shí)會(huì)改變狀態(tài)??磖esolve,reject的函數(shù)聲明
*? ? ? 2,new Promise時(shí)傳入的函數(shù)為什么要立即執(zhí)行,then里傳的兩個(gè)函數(shù)為什么要異步執(zhí)行?
*? ? ? ? ? resolve,reject函數(shù)是用戶決定什么時(shí)候執(zhí)行的,同步、異步執(zhí)行都是用戶的行為
*? ? ? ? ? 這里可以好好分析下,信息量很大
*/
/*
* 狀態(tài)確定后挨個(gè)調(diào)用數(shù)組中的方法
* 狀態(tài)是在resolve,reject函數(shù)執(zhí)行時(shí)改變的
*/
function Promise(executor) {
var self = this
/*
* 為什么要?jiǎng)?chuàng)建數(shù)組?
* new出第一個(gè)實(shí)例promise后,可以調(diào)用多次then
* 而此時(shí)promise的狀態(tài)可能還不確定,所以來(lái)個(gè)數(shù)組保存下then中的函數(shù),等到狀態(tài)確定后再執(zhí)行then中的函數(shù)。
* 保存then中的回調(diào)函數(shù),注意查看什么時(shí)候push進(jìn)去的
*/
self.resolvedCallbacks = []
self.rejectedCallbacks = []
// 狀態(tài)
self.status = 'pending'
/*
* resolve中應(yīng)該包含一個(gè)對(duì)象,因?yàn)槊看蝿?chuàng)建一個(gè)實(shí)例
* 彼此間都不會(huì)有影響(這難道不是單例模式么?還是工廠函數(shù)?)
* 狀態(tài)[確定]后挨個(gè)調(diào)用數(shù)組中的方法,必須被當(dāng)做函數(shù)調(diào)用。
* 即調(diào)用時(shí)函數(shù)體內(nèi)的this應(yīng)該是undefined/window
* --------------------------------------------------
* 成功傳值,失敗傳原因
* --------------------------------------------------
* resolve和reject是什么時(shí)候被執(zhí)行的呢?
* 這兩個(gè)函數(shù)是在executor體內(nèi)被執(zhí)行的
* --------------------------------------------------
* 對(duì)于在resolve,reject兩個(gè)函數(shù)中
* 異步執(zhí)行resolvedCallbacks,rejectedCallbacks中函數(shù)問(wèn)題
*
*/
function resolve(value) {
// 測(cè)試用例給我們傳了一個(gè)我自己定義的Promise實(shí)例時(shí)
if (value instanceof Promise) {
value.then(resolve, reject)
return
}
// 這里為什么也要異步
// 因?yàn)閿?shù)組resolvedCallbacks,rejectedCallbacks不能跟resolve同步執(zhí)行。為什么?
setTimeout(function() {
/*
* 這里是為了確保狀態(tài)不可改變,即resolve/reject只執(zhí)行一次
*/
if (self.status === 'pending') {
self.status = 'resolved'
// 保存?zhèn)魅氲膮?shù),promise成功時(shí)的值
self.data = value
var f
// 性能優(yōu)先,使用原始for循環(huán)
for (var i = 0; i < self.resolvedCallbacks.length; i++) {
/*
* 為什么分開(kāi)寫?
* 確保是函數(shù)的調(diào)用,即被調(diào)用時(shí)函數(shù)體內(nèi)的this為undefined/window
* 標(biāo)準(zhǔn)里都有說(shuō)明
*/
f = self.resolvedCallbacks[i]
f(value)
}
}
})
}
function reject(reason) {
// 為什么是異步
setTimeout(function() {
if (self.status === 'pending') {
self.status = 'rejected'
self.data = reason
var f
for (var i = 0; i < self.rejectedCallbacks.length; i++) {
f = self.rejectedCallbacks[i]
f(reason)
}
}
})
}
try {
// promise創(chuàng)建時(shí)傳入的函數(shù)會(huì)立即執(zhí)行,而傳入的函數(shù)不知道有沒(méi)有問(wèn)題.所以要try下
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
/*
* then方法中實(shí)現(xiàn)根據(jù)狀態(tài)調(diào)用不同的函數(shù),
* 并且在調(diào)用回調(diào)前返回一個(gè)新的promise且此promise的狀態(tài)由回調(diào)函數(shù)確定
*? pending -> fulfilled : 調(diào)用onResolved
*? pending -> rejected : 調(diào)用onRejected
*? onRejected\onResolved必須是函數(shù),否則忽略它
*/
Promise.prototype.then = function(onResolved, onRejected) {
var self = this
if (typeof onResolved !== 'function') {
/*
* 為什么要這樣?
* 例如這種情況:p2 = p1.then(null, f2),沒(méi)有傳onResolved函數(shù)
*? p1成功了,應(yīng)該調(diào)用onResolved函數(shù)。
*? 正常情況下p2的狀態(tài)由onResolved確定,而onResolved沒(méi)有東西。
*? 此時(shí)p2的狀態(tài)應(yīng)該由p1決定。
*? 怎么拿到p1的狀態(tài)?在then中成功時(shí)調(diào)用的函數(shù)將p1的狀態(tài)返回就拿到p1的狀態(tài)!
*? 在沒(méi)有返回函數(shù)情況下,將onResolved用一個(gè)函數(shù)代替
* ---------------------------------------------------------------
*? 為什么可以這么寫,我沒(méi)有吃透
*
*? 這個(gè)函數(shù)被執(zhí)行的時(shí)候value就有值了,狀態(tài)改變onResolved(self.data)執(zhí)行
*? 在這種情況下value的值查查self.data
*? self.data是在構(gòu)造函數(shù)里的resolve(value)里被賦值的。所以這里非常的繞,還需要再來(lái)理解消化
*
*/
onResolved = function(value) { return value }
}
if (typeof onRejected !== 'function') {
/*
* 為什么要這樣?
* 例如這種情況:p2 = p1.then(null, f2),沒(méi)有傳onResolved函數(shù)
*? p1失敗,p2也應(yīng)該失敗。
*? 這里throw,后面的try可以catch到。catch到就會(huì)reject(e)
*? 將p1的失敗reason拋出來(lái),p2也就失敗了
*? 具體的過(guò)程跟上面的函數(shù)是一樣的
*/
onRejected = function(reason) { throw reason}
}
/*
* 實(shí)例在三種狀態(tài)下都可以調(diào)用then方法
* 判斷狀態(tài)的三種情況。為了方便
* 在三種情況下
* 我要實(shí)現(xiàn)的是
*/
var promise2
if (self.status === 'resolved') {
/*
* 返回一個(gè)新的promise2,在promise2中調(diào)用onResolved且傳入promise成功時(shí)傳入的值
* 而promise成功時(shí)傳入的值到底是什么,我們是不知道的。
* 這是promise中最復(fù)雜的?。?!
* ----------------------------------------------------------------------
* onResolved返回值x決定了promise2的狀態(tài)
*
*/
promise2 = new Promise(function(resolve, reject) {
// 為什么這里要異步?TODO
setTimeout(function() {
try {
/*
* 這個(gè)data是第一個(gè)promise中傳入的函數(shù)中的resolve攜帶的參數(shù)?。。?!
* onResolved是在then里的,
* 如果onResolved返回的又是Promise實(shí)例x呢,
* --------------------------------------------------------------
* 這次的promise的狀態(tài)是由返回的新的Promise實(shí)例決定
* 而新的實(shí)例的狀態(tài)什么時(shí)候確定呢?我們不用管,只需要在其后掛個(gè)then。
* then中函數(shù)運(yùn)行的時(shí)候就是狀態(tài)確定的時(shí)候
* --------------------------------------------------------------
* 直接resolve是不行的,需要在返回的實(shí)例x中的then里resolve值
*/
var x = onResolved(self.data)
// 非兼容
// if (x instanceof Promise) {
//? // 非簡(jiǎn)化。可以想想了,又是遞歸?
//? // x.then(function(value) {
//? //? resolve(value)
//? // }, function(reason) {
//? //? reject(reason)
//? // })
//? // 簡(jiǎn)化
/*
* 這種簡(jiǎn)化讓人頭疼,resolve,reject是需要傳參的。問(wèn)題來(lái)了,兩個(gè)函數(shù)的參數(shù)是怎么傳進(jìn)去的
* 這里的resolve,reject其實(shí)就是onResolved和onRejected。這種情況又是遞歸了
*/
//? x.then(resolve, reject)
// } else {
//? resolve(x)
// }
// 兼容下
RESOLVE_PROMISE(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
})
}
if (self.status === 'rejected') {
promise2 = new Promise(function(resolve, reject) {
// 為什么這里要異步?TODO
setTimeout(function() {
try {
var x = onRejected(self.data)
// 非兼容,如果x是Bluebird,Q里的promise呢?if就不會(huì)執(zhí)行了
// if (x instanceof Promise) {
//? x.then(resolve, reject)
// } else {
//? // 為什么是resolve?
//? resolve(x)
// }
// 兼容
RESOLVE_PROMISE(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
})
}
if (self.status === 'pending') {
/*
* promise1還是不確定狀態(tài),需要等到promise1確地了狀態(tài)才能確定promise2應(yīng)該怎么走
* 查看構(gòu)造函數(shù)里resolve函數(shù)的注釋,找找靈感。
* -------------------------------------------------------
* 為什么在這就不需要像上面的‘resolved’,‘rejected’里異步呢?
*? ? 因?yàn)檫@里肯定是在將來(lái)才執(zhí)行的
*/
promise2 = new Promise(function(resolve, reject) {
self.resolvedCallbacks.push(function(value) {
try {
var x = onResolved(self.data)
// 非兼容
// if (x instanceof Promise) {
//? x.then(resolve, reject)
// } else {
//? resolve(x)
// }
// 兼容
RESOLVE_PROMISE(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
self.rejectedCallbacks.push(function(reason) {
try {
var x = onRejected(self.data)
// 非兼容
// if (x instanceof Promise) {
//? x.then(resolve, reject)
// } else {
//? resolve(x)
// }
// 兼容
RESOLVE_PROMISE(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
})
})
}
return promise2
}
/*
* 上面就基本已經(jīng)實(shí)現(xiàn)了Promise,但是沒(méi)有達(dá)到 https://promisesaplus.com/ 規(guī)范的要求。
* 這個(gè)函數(shù)是多種實(shí)現(xiàn)中的一種
* 這個(gè)函數(shù)的作用是使其他的Promise可以互相兼容------兼容
* ------------------------------------------------------------------------
* 各參數(shù)說(shuō)明
*? ? promise:
*? ? x:
*? ? resolve:
*? ? reject:
*/
function RESOLVE_PROMISE(promise, x, resolve, reject) {
if (promise === x) {
// 一個(gè)promise實(shí)例resolve了它自己
reject(new TypeError('Chaining cycle is deteced for promise'))
return
}
// 如果x是自己的Promise的實(shí)現(xiàn)
if (x instanceof Promise) {
if (x.status === 'pending') {
x.then(function(v) {
// god,又是遞歸
RESOLVE_PROMISE(promise, v, resolve, reject)
}, reject)
} else {
x.then(resolve, reject)
}
return
}
// 只有對(duì)象和函數(shù)這兩種數(shù)據(jù)類型可以保存屬性,然而typeof null也是'object'
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
/*
* 為什么要把then單獨(dú)拿出來(lái)?避免副作用
*? 因?yàn)槲覀兪窃谧x別人給的屬性,但是我們不知道該屬性具體是什么。也可能報(bào)錯(cuò)
*? 如果該屬性是getter,則每次調(diào)用就會(huì)返回不同的值。
* 所以只調(diào)用一次
* ---------------------------------------------------------------------
* a,b,c三者只能調(diào)用一個(gè),為什么?TODO
*? 避免原型鏈上有then函數(shù)(thenable)但卻不是Promise的實(shí)現(xiàn),但是為什么這樣就可以避免,我并沒(méi)有吃透
* ---------------------------------------------------------------------
* if語(yǔ)句里有兩個(gè)可以可疑的函數(shù),有函數(shù)名resolvePromise,rejectPromise。
* 既然是當(dāng)參數(shù)傳,我覺(jué)得不需要函數(shù)名應(yīng)該也一樣吧
*/
var then = x.then
var called = false // 記錄執(zhí)行狀態(tài)
if (typeof then === 'function') {
then.call(x, function resolvePromise(y) {
if (called) {
return
}
called = true
// 產(chǎn)生了遞歸
RESOLVE_PROMISE(promise, y, resolve, reject)//--- a
}, function rejectPromise(r) {
if (called) {
return
}
called = true
reject(r) //------------------------------------- b
})
} else {
resolve(x)
}
} catch(e) {
if (called) {
return
}
called =true
reject(e) //----------------------------------------- c
}
} else {
resolve(x)
}
}