Promise
Promise A+ 规范实现
const PENDING = 'PENDING' // 等待
const FULFILLED = 'FULFILLED' // 成功
const REJECTED = 'REJECTED' // 失败
// 该方法核心就是判断x
const resolvePromise = (promise2, x, resolve, reject) => {
// 判断x和promise2是不是同一个人,是则就报错
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<Promise>')
)
}
let called // 内部测试的时候 成功和失败都调用
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call(
x,
(y) => {
// y 可能还是一个promise,递归调用,直到解析为一个普通值为止
if (called) {
return
}
called = true
resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) {
return
}
called = true // 防止多次调用成功和失败
reject(r)
}
)
} else {
resolve(x) // {then: 1} 说明x 是一个普通对象,直接成功即可
}
} catch (error) {
if (called) {
return
}
called = true
reject(error)
}
} else {
// x 不是对象或函数 肯定是一个普通值
resolve(x)
}
}
class Promise {
constructor(executor) {
// 不能相信用户的输入,一定要进行参数校验
if (typeof executor !== 'function') {
throw new TypeError(` Promise resolver ${executor} is not a function `)
}
this.status = PENDING
this.value = undefined // 成功的值
this.reason = undefined // 失败的原因
this.onResolvedCallbacks = [] // 成功的回调的数组
this.onRejectedCallbacks = [] // 失败的回调的数组
// 成功函数
let resolve = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED
this.onResolvedCallbacks.forEach((fn) => fn()) // 发布
}
}
// 失败函数
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
this.onRejectedCallbacks.forEach((fn) => fn())
}
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onfulfilled, onrejected) {
onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : (val) => val
onrejected =
typeof onrejected === 'function'
? onrejected
: (err) => {
throw err
}
let promise2 = new Promise((resolve, reject) => {
// 同步情况
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onfulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onrejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
}
// 异步情况
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onfulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onrejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (error) {
reject(error)
}
}, 0)
})
}
})
return promise2
}
}
Promise.defer = Promise.deferred = function() {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
module.exports = Promise
通过第三方依赖包来检测编写的 Promise 是否符合规范:
npm install promises-aplus-tests
promises-aplus-tests ./myPromise.js
常见问题:
为什么要加定时器?
因为 JS 执行机制,new Promise 没有执行完就传 promise2,报 promise2 未定义
为什么在处理异步情况的时候也要加 try-catch?
加了异步 setTimeout 后;若代码里直接 throw new Error 抛错的话,上面的异常处理捕捉不到,因为是同步的,我们加了 setTimeout 后该部分就变成异步的了,所以我们需要在处理异步的情况时候也要加个异常处理 try catch