Skip to content

Instantly share code, notes, and snippets.

@yshwaker
Last active November 20, 2022 07:04
Show Gist options
  • Save yshwaker/aea34aa9b44ca20187010e3b4ecf9b0b to your computer and use it in GitHub Desktop.
Save yshwaker/aea34aa9b44ca20187010e3b4ecf9b0b to your computer and use it in GitHub Desktop.
Promise Implementation
function addToTaskQueue(fn) {
// 模拟浏览器微任务
setTimeout(fn, 0)
}
function isThenable(value) {
return typeof value?.then === 'function';
}
class MyPromise {
#state
#value
#handlers
constructor(fn) {
this.#state = 'pending'
this.#value = null
this.#handlers = []
this.#safeRun(fn, this.#resolve, this.#reject)
}
#safeRun = (fn, onFulfilled, onRejected) => {
let done
try {
fn(
(val) => {
if (done) {
return
}
done = true
onFulfilled(val)
},
(val) => {
if (done) {
return
}
done = true
onRejected(val)
}
)
} catch (err) {
if (done) {
return
}
done = true
onRejected(err)
}
}
#resolve = (value) => {
if (isThenable(value)) {
this.#safeRun(value.then, this.#resolve, this.#reject)
} else {
this.#fulfill(value)
}
}
#fulfill = (value) => {
this.#state = 'fulfilled'
this.#value = value
this.#handlers.forEach(this.#handle)
this.#handlers = null // garbage collecting
}
#reject = (err) => {
this.#state = 'rejected'
this.#value = err
this.#handlers.forEach(this.#handle)
this.#handlers = null // garbage collecting
}
#handle = (handler) => {
if (this.#state === 'pending') {
this.#handlers.push(handler)
}
if (this.#state === 'fulfilled') {
handler.onFulfilled(this.#value)
}
if (this.#state === 'rejected') {
handler.onRejected(this.#value)
}
}
then = (onFulfilled, onRejected) => {
const nextPromise = new MyPromise((resolve, reject) => {
const fullfillmentTask = () => {
const value =
typeof onFulfilled === 'function' ? onFulfilled(this.#value) : this.#value
resolve(value)
}
const rejectionTask = () => {
const value =
typeof onRejected === 'function' ? onRejected(this.#value) : this.#value
resolve(value)
}
addToTaskQueue(() => {
this.#handle({
onFulfilled: fullfillmentTask,
onRejected: rejectionTask,
})
})
})
return nextPromise
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment