目录
参考资料
Promises 介绍文档
Promises/A+ 规范
Promises 的一种实现方式
github 上 2.6k+ star 的一个 Promise 实现方式
手写 Promise
自己手动实现的简易版 Promise
,便于理解 Promise
工作原理。以下实现版本,并未完全 compilant to Promises/A+ 规范,但对于用户理解 Promise 工作原理已有很大帮助。
myPromise.js
let PENDING = 'pending'
let FULFILLED = 'fulfilled'
let REJECTED = 'rejected'
class Promise {
state
value
handlers = []
constructor(executor) {
this.state = PENDING
try {
executor(this.#resolve.bind(this), this.#reject.bind(this))
} catch (err) {
this.#reject(err)
}
}
#resolve(data) {
this.#changeState(FULFILLED, data)
}
#reject(err) {
this.#changeState(REJECTED, err)
}
#changeState(newState, data) {
// 状态只能改变一次
if (this.state !== PENDING) return
this.state = newState
this.value = data
// 检查一下是否有 then() 添加的 handler,如果有,就将这些 handler 包装成 task 放入 micro task queue
this.#runHandlers()
}
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
this.handlers.push(new Handler(onFulfilled, onRejected, resolve, reject))
this.#runHandlers()
})
}
/**
*
* 将所有 handler 放入 microt task queue,不会阻塞很长时间
*/
#runHandlers() {
if (this.state === PENDING) return
while (this.handlers.length > 0) {
const handler = this.handlers.shift()
runMicroTask(() => {
const { onFulfilled, onRejected, resolve, reject } = handler
const onHandler = (this.state === FULFILLED) ? onFulfilled : onRejected
const resolveOrReject = (this.state === FULFILLED) ? resolve : reject
if (onHandler) {
try {
const result = onHandler(this.value)
if (isPromise(result)) {
result.then(resolve, reject)
} else {
resolve(result)
}
} catch (ex) {
reject(ex)
}
} else {
resolveOrReject(this.value)
}
})
}
}
}
/**
*
* @param {*} value onFulfilled/onRejected 返回的值
* @returns true: 是 Promise; false: 不是 Promise
* @reference 参考 Promises/A+规范:https://promisesaplus.com/
* @reference 1.1 “promise” is an object or function with a then method whose behavior conforms to this specification.
*/
function isPromise(value) {
return ((typeof value === 'object' || typeof value === 'function') && typeof value.then === 'function')
}
/**
*
* @param {*} task 将要放入 micro task queue 的任务
*/
function runMicroTask(task) {
if (typeof process === 'object' && typeof process.nextTick === 'function') {
process.nextTick(task) // nodejs 环境,将 task 放入 micro task queue
} else {
setTimeout(task, 0) // 这里其实将 task 放入了 macro task queue
}
}
class Handler {
constructor(onFulfilled, onRejected, resolve, reject) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.resolve = resolve;
this.reject = reject;
}
}
export default Promise;
测试运行
testPromise.js
const Promise = require('./myPromise.js')
let p = new Promise((resolve) => {
setTimeout(() => {
resolve(200)
console.log('timeout, p:', p)
}, 3000)
})
p.then((val) => {
console.log('the very first then, value:', val)
})
p.then((val) => {
console.log('first then, value:', val)
return new Promise((res, rej) => {
res(val + 1)
})
}).then((val) => {
console.log('second then, value:', val)
return new Promise((res, rej) => {
rej(val + 1)
})
}).then(null, (val) => {
console.log('third then, rejected, value:', val)
throw (val + 1)
}).then(null, (val) => {
console.log('forth then, rejected, value:', val)
return val + 1
}).then((val) => {
console.log('fifth then, value:', val)
})
执行结果
$ node testPromise.js
timeout, p: Promise { state: 'fulfilled', value: 200, handlers: [] }
the very first then, value: 200
first then, value: 200
second then, value: 201
third then, rejected, value: 202
forth then, rejected, value: 203
fifth then, value: 204
标签:resolve,val,value,task,Promise,reject,手写
From: https://www.cnblogs.com/dongling/p/18018039