我的思路是根據這個Promise的使用方法,一步步用js還原其原理
// 這個回調函數傳進來就開始執行了
let oP = new Promise((resolve, reject) => {
resolve(1)
})
// 這個要根據你的狀態進行選擇 Fulfilled pending Rejected
oP.then((res) => {
console.log(res)
}, (rej)=> {
console.log(rej)
})
// 源碼實現
// Fulfilled pending Rejected
function MyPromise(executor) {
let self = this
this.status = 'pending'
this.resolveValue = null
this.rejectValue = null
this.ResolveCallBackList = []
this.RejectCallBackList = []
function resolve(val) {
if(self.status === 'pending') {
self.status = 'Fulfilled'
self.resolveValue = val
}
}
function reject(reason) {
if(self.status === 'pending') {
self.status = 'Rejected'
self.rejectValue = reason
}
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
MyPromise.prototype.then = function(onFulfilled, onRejected) {
let self = this
if(this.status === 'Fulfilled') {
onFulfilled(self.resolveValue)
}
if(this.status === 'Rejected') {
onRejected(self.rejectValue)
}
}
現在有了初步的實現,我們繼續完善功能,如果是出現如下情況
let oP = new MyPromise((resolve, reject) => {
// resolve函數放在了異步事件中,那麼此時then函數會先於resolve執行
// then函數無法拿到resolve函數所傳的值
setTimeout(() => {
resolve(1)
});
})
解決方法:構造函數定義一個回調列表,分別對應
Fulfilled Rejected 這個狀態
// Fulfilled pending Rejected
function MyPromise(executor) {
let self = this
this.status = 'pending'
this.resolveValue = null
this.rejectValue = null
this.ResolveCallBackList = []
this.RejectCallBackList = []
function resolve(val) {
if (self.status === 'pending') {
self.status = 'Fulfilled'
self.resolveValue = val
self.ResolveCallBackList.forEach(item => {
item()
})
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'Rejected'
self.rejectValue = reason
self.RejectCallBackList.forEach(item => {
item()
})
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this
if (this.status === 'Fulfilled') {
onFulfilled(self.resolveValue)
}
if (this.status === 'Rejected') {
onRejected(self.rejectValue)
}
if (this.status === 'pending') {
self.ResolveCallBackList.push(function () {
onFulfilled(self.resolveValue)
})
self.RejectCallBackList.push(function () {
onRejected(self.rejectValue)
})
}
}
繼續添加功能:
功能1:由於then函數是一個微任務事件,這裏我們使用setTimeout進行模擬
功能2:實現then函數的一個鏈式調用
功能3:then函數中出異常,利用try、catch進行處理
功能四:如果是then函數傳入的參數出現空值,那麼需要對參數進行非空判斷並且進行重寫
// Fulfilled pending Rejected
function MyPromise(executor) {
let self = this
this.status = 'pending'
this.resolveValue = null
this.rejectValue = null
this.ResolveCallBackList = []
this.RejectCallBackList = []
function resolve(val) {
if (self.status === 'pending') {
self.status = 'Fulfilled'
self.resolveValue = val
self.ResolveCallBackList.forEach(item => {
item()
})
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'Rejected'
self.rejectValue = reason
self.RejectCallBackList.forEach(item => {
item()
})
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
if(!onFulfilled) {
onFulfilled = function(val) {
return val
}
}
if(!onRejected) {
onRejected = function(reason) {
return reason
}
}
let self = this
let nextPromise = new MyPromise(function (res, rej) {
if (self.status === 'Fulfilled') {
setTimeout(() => {
try {
let returnValue = onFulfilled(self.resolveValue)
res(returnValue)
} catch (e) {
rej(e)
}
})
}
if (self.status === 'Rejected') {
setTimeout(() => {
try {
let returnValue = onRejected(self.rejectValue)
rej(returnValue)
} catch (e) {
rej(e)
}
})
}
if (self.status === 'pending') {
self.ResolveCallBackList.push(function () {
setTimeout(() => {
try {
let returnValue = onFulfilled(self.resolveValue)
res(returnValue)
} catch (e) {
rej(e)
}
})
})
self.RejectCallBackList.push(function () {
setTimeout(() => {
try {
let returnValue = onRejected(self.rejectValue)
rej(returnValue)
} catch (e) {
rej(e)
}
})
})
}
})
return nextPromise
}
最後一個功能:then函數中的參數(參數是個函數)返回的是一個MyPromise對象,我們應該如何處理。案例如下:
let oP = new Promise((resolve, reject) => {
resolve(1)
})
// 這裏有兩個promise之間的關係問題,實際上也是我們需要解決的問題
oP.then((res) => {
console.log(res)
return new Promise((res, rej) => {
res(1) // 這個返回來的Promise對象最後賦值給then函數的內部變量
})
}).then(res => {
console.log('then: ', res)
})
解決方法:
// Fulfilled pending Rejected
function MyPromise(executor) {
let self = this
this.status = 'pending'
this.resolveValue = null
this.rejectValue = null
this.ResolveCallBackList = []
this.RejectCallBackList = []
function resolve(val) {
if (self.status === 'pending') {
self.status = 'Fulfilled'
self.resolveValue = val
self.ResolveCallBackList.forEach(item => {
item()
})
}
}
function reject(reason) {
if (self.status === 'pending') {
self.status = 'Rejected'
self.rejectValue = reason
self.RejectCallBackList.forEach(item => {
item()
})
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
function ResolutionReturnPromise(returnValue, res, rej) {
if(returnValue instanceof MyPromise) {
returnValue.then((val) => {
res(val)
}, (reason) => {
rej(reason)
})
} else {
res(returnValue)
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
if(!onFulfilled) {
onFulfilled = function(val) {
return val
}
}
if(!onRejected) {
onRejected = function(reason) {
return reason
}
}
let self = this
let nextPromise = new MyPromise(function (res, rej) {
if (self.status === 'Fulfilled') {
setTimeout(() => {
try {
let returnValue = onFulfilled(self.resolveValue)
ResolutionReturnPromise(returnValue, res, rej)
} catch (e) {
rej(e)
}
})
}
if (self.status === 'Rejected') {
setTimeout(() => {
try {
let returnValue = onRejected(self.rejectValue)
ResolutionReturnPromise(returnValue, res, rej)
} catch (e) {
rej(e)
}
})
}
if (self.status === 'pending') {
self.ResolveCallBackList.push(function () {
setTimeout(() => {
try {
let returnValue = onFulfilled(self.resolveValue)
ResolutionReturnPromise(returnValue, res, rej)
} catch (e) {
rej(e)
}
})
})
self.RejectCallBackList.push(function () {
setTimeout(() => {
try {
let returnValue = onRejected(self.rejectValue)
ResolutionReturnPromise(returnValue, res, rej)
} catch (e) {
rej(e)
}
})
})
}
})
return nextPromise
}
這裏是個初稿,太困了,後續再附上詳細說明和修正