更新
最近看到一個實現(xiàn)胆胰,講得更加清晰,于是重新實現(xiàn)了一遍
class GePromise {
constructor(fn) {
this.state = 'pending'
this.value = undefined
this.resolvedCb = []
this.rejectedCb = []
let self = this
try {
let resolve = self.__resolve.bind(self)
let reject = self.__reject.bind(self)
fn(resolve, reject)
} catch (e) {
self.__reject(e)
}
}
__resolve(value) {
let self = this
if (value instanceof GePromise) {
return value.then(self.__resolve, self.__reject)
}
setTimeout(() => {
self.state = 'resolved'
self.value = value
self.resolvedCb.forEach(cb => cb())
}, 0)
}
__reject(reason) {
let self = this
setTimeout(() => {
self.state = 'rejected'
self.value = reason
self.rejectedCb.forEach(cb => cb())
}, 0)
}
then(onResolved, onRejected) {
let self = this
let state = this.state
let newPromise
if (state === 'resolved') {
newPromise = new GePromise((resolve, reject) => {
setTimeout(() => {
try {
let x = onResolved(self.value)
self.value = x
resolve(x)
} catch (reason) {
reject(reason)
}
}, 0)
})
} else if (state === 'rejected') {
newPromise = new GePromise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(self.value)
self.value = x
resolve(x)
} catch (reason) {
reject(reason)
}
}, 0)
})
} else if (state === 'pending') {
newPromise = new GePromise((resolve, reject) => {
self.resolvedCb.push(() => {
try {
let x = onResolved(self.value)
self.value = x
resolve(x)
} catch (reason) {
reject(reason)
}
})
self.rejectedCb.push(() => {
try {
let x = onRejected(self.value)
self.value = x
resolve(x)
} catch (reason) {
reject(reason)
}
})
})
}
return newPromise
}
}
const simpleTest = () => {
let a = new GePromise((res, rej) => {
setTimeout(() => {
console.log('set timeout')
res('resolve')
}, 1000)
})
let b = a.then((res) => {
console.log(res) // resolve
return 'after resolve'
}, (rej) => {
console.error(rej)
return 'first reject'
}).then(res => {
console.log(res) // after resolve
})
}
原文
之前看到朋友實現(xiàn)了一個promise垮斯,覺得挺好玩的郎仆,心中躍躍欲試,于是近期看了一些文章兜蠕,自己也跟著實現(xiàn)了一遍扰肌,記錄下來。
promise是為了解決回調(diào)地獄熊杨,它是通過then方法來注冊回調(diào)函數(shù)曙旭,使得代碼在組織上更加清晰盗舰。
一個簡單的雛形:
class GePromise {
constructor(fn) {
this.value = null
this.callbacks = []
this.init(fn)
}
init(fn) {
const self = this
const resolve = function(value) {
self.callbacks.forEach((callback) => {
callback(value)
})
}
fn(resolve)
}
then(fn) {
this.callbacks.push(fn)
return this
}
}
const test_1 = function () {
const p = new GePromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
console.log(2)
})
p.then((val) => {
console.log(val)
})
}
test_1()
這時候會有一個問題,有可能在then注冊好回調(diào)之前桂躏,resolve就執(zhí)行了钻趋,因此加入延時機制:
...
const resolve = function(value) {
setTimeout(() => {
self.callbacks.forEach((callback) => {
callback(value)
})
}, 0)
}
...
引入狀態(tài)控制:
class GePromise {
constructor(fn) {
this.state = 'pending'
this.value = null
this.callbacks = []
this._init(fn)
}
_init(fn) {
const resolve = this._resolve.bind(this)
fn(resolve)
}
_resolve(value) {
const self = this
self.value = value
self.state = 'fulfilled'
setTimeout(() => {
self.callbacks.forEach((callback) => {
callback(value)
})
}, 0)
}
then(fn) {
if (this.state === 'pending') {
this.callbacks.push(fn)
} else {
const val = this.value
fn(val)
}
return this
}
}
const test = function () {
const p = new GePromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000)
console.log(2)
})
p.then((val) => {
console.log(val)
})
setTimeout(() => {
p.then((val) => {
console.log(3)
})
}, 3000)
}
test()
最后加入reject:
class GePromise {
constructor(fn) {
this.state = 'pending'
this.value = null
this.successCb = []
this.errorCb = []
this._init(fn)
}
_init(fn) {
const resolve = this._resolve.bind(this)
const reject = this._reject.bind(this)
fn(resolve, reject)
}
_resolve(value) {
const self = this
self.value = value
self.state = 'fulfilled'
setTimeout(() => {
self.successCb.forEach((callback) => {
callback(value)
})
}, 0)
}
_reject(reason) {
const self = this
self.value = reason
self.state = 'rejected'
setTimeout(() => {
self.errorCb.forEach((callback) => {
callback(reason)
})
}, 0)
}
then(fn) {
if (this.state === 'pending') {
this.successCb.push(fn)
} else {
const val = this.value
fn(val)
}
return this
}
catch(fn) {
if (this.state === 'pending') {
this.errorCb.push(fn)
} else {
const val = this.value
fn(val)
}
return this
}
}