promise 实现
大约 4 分钟
promise 实现
实现标准
promise
经常用来处理异步任务,它的实现标准在 Promises/A+ 规范中有明确描述:
“promise” is an object or function with a then method whose behavior conforms to this specification.
“thenable” is an object or function that defines a then method.
“value” is any legal JavaScript value (including undefined, a thenable, or a promise).
“exception” is a value that is thrown using the throw statement.
“reason” is a value that indicates why a promise was rejected.
由以上规范的描述可知, promise
是一个具有 then()
方法的对象
具体实现
下面是按照 Promises/A+ 规范来实现的 promise
方法:
//定义 promise 的三种状态,这三种状态之间是互斥的
const PENDING = 'pending' //还在执行或者挂起状态
const FULFILLED = 'fulfilled' //执行成功状态
const REJECTED = 'rejected' //执行失败状态
//判断一个值是否是 promise
function isPromiseLike(value) {
//根据 promise/A+ 规范判断传入的值是否是对象/函数,并且它是否具有 then 方法
if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
return value.then && typeof value.then === 'function'
}
return false
}
//模拟微任务,将 promise 执行的回调放入微任务队列中
function microTask(callback) {
//判断浏览器环境
if (MutationObserver && typeof MutationObserver === 'function') {
const tag = 'div'
const ob = new MutationObserver(callback)
const el = document.createElement(tag)
ob.observe(el, { attributes: true })
el.dataset.name = tag
}
//判断 node 环境
else if (process && typeof process === 'object' && typeof process.nextTick === 'function') {
process.nextTick(callback)
}
//其他环境
else {
setTimeout(callback, 0)
}
}
function myPromise(executor) {
//这里通过闭包来模拟私有属性
let state = PENDING //promise 的初始状态设置为 'pending'
let result = undefined //promise 的初始结果不确定,设置为 undefined
const handlers = [] //promise 的 then 方法中收集相关传入参数的数组集合
// promise 改变状态的方法
const stateChange = (next, value) => {
//根据 promise/A+ 规范,promise 状态一旦改变,就确定下来不会再变化了
//这里对 state 进行判断,防止重复触发改变 promise 的状态
if (state !== PENDING) return
state = next
result = value
//当状态变化时执行此方法
onStateChange()
}
//promise 成功回调
const resolve = (value) => {
stateChange(FULFILLED, value)
}
//promise 失败回调
const reject = (reason) => {
stateChange(REJECTED, reason)
}
//当 promise 状态发生改变时执行的方法
const handleStateChange = (callback, resolve, reject) => {
//这里执行 then 方法中传入的参数要分三种情况:
//1.传入的参数是函数 2.传入的参数是 promise 3.传入的参数不是函数
microTask(() => {
if (callback && typeof callback === 'function') {
try {
//这里使用 try / catch 处理前两种情况
//将promise的执行结果传入回调函数中,获取回调函数的返回结果
const res = callback(result)
//判断结果是否是 promise
if (isPromiseLike(res)) {
//是 promise 则调用它的 then 方法
res.then(resolve, reject)
} else {
//不是 promise 则直接将结果 resolve
resolve(res)
}
} catch (error) {
//在这里捕获回调执行的错误情况
reject(error)
}
} else {
//这里处理传入参数不是函数/不是promise的情况
const handler = state === FULFILLED ? resolve : reject
handler(result)
}
})
}
//promise 状态变化执行的方法
const onStateChange = () => {
//如果 promise 的状态还在执行,没有发生变化,就不应该触发 then 方法的回调
if (state === PENDING) return
//通过 while 循环从 保存 then 方法的相关参数的集合中取出每一个参数集合执行
//这里因为 then 方法可以支持链式调用,所以用数组来存储,通过遍历来取出
while (handlers.length > 0) {
const { onFulfilled, onRejected, resolve, reject } = handlers.shift()
//当 promise 执行成功,状态改变为 'fulfilled' 时
if (state === FULFILLED) {
handleStateChange(onFulfilled, resolve, reject)
}
//当 promise 执行失败,状态改变为 'rejected' 时
else if (state === REJECTED) {
handleStateChange(onRejected, resolve, reject)
}
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
//promise 的 then 方法,这里是关键,根据 promise/A+ 规范 then 必须返回一个 promise
this.then = function (onFulfilled, onRejected) {
return new myPromise((resolve, reject) => {
//这里由于我们无法确定 promise 在什么时候能完成(即不知道 promise 的状态在何时发生改变),
//所以将 then 方法中的相关回调函数全部收集起来,等待状态变更时调用
handlers.push({
onFulfilled,
onRejected,
resolve,
reject
})
//promise 状态变更时会执行此方法的逻辑
onStateChange()
})
}
//catch 方法实际上是只穿传入了 onRejected 的 then 方法
this.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
//finally 方法没有参数,并且返回一个与原 promise 状态相同的 promise 对象
this.finally = function (callback) {
return this.then(
(value) => {
return myPromise.resolve(callback()).then(() => {
return value
})
},
(reason) => {
return myPromise.resolve(callback()).then(() => {
throw reason
})
}
)
}
}
//myPromise 的静态方法 resolve
myPromise.resolve = function (value) {
return new myPromise((resolve, reject) => {
if (isPromiseLike(value)) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
//myPromise 的静态方法 reject
myPromise.reject = function (reason) {
return new myPromise((_, reject) => {
reject(reason)
})
}
//使用
const p = new myPromise((resolve, reject) => {
resolve(1)
//setTimeout(() => resolve(1), 1000)
})
p.then(
(res) => {
console.log('ok', res)
return 123
}
).then(
(res) => {
console.log('ok', res)
return res * 2
}
).then(123, (err) => {
console.log('error', err)
}).then(
(res) => {
console.log('ok', res)
return res * 2
},
)
//输出:
// ok 1
// ok 123
// ok 246