手写一个符合Promise A+规范的Promise实现
吴佳
2020-05-29 14:33:42
5678
2
0
前言
记得之前发过一篇关于Promise文章的讲解,不过都不是很深入,只是对使用上的理解,所以这次我将会带着各位通过JavaScript来实现一个Promise,并且是符合规范的,最后可以通过promises-aplus-tests来进行跑测。
整个实现主要通过Promise A+规范来做的,可以参考以下地址:
https://promisesaplus.com/
正文
接下来的内容我将直接贴出源码,因为我在写的时候都以逐行加了注释来说明代码理解,所以就不会再来逐行解读了,如各位从其中发现任何问题欢迎留言指正
utils.js 文件
const {
PENDING,
FULFILLED,
REJECTED,
getType,
isArray,
isObject,
isFunction
} = {
PENDING: 'pending',
FULFILLED: 'fulfilled',
REJECTED: 'rejected',
getType: (t) => (v) => Object.prototype.toString.call(v) === `[object ${t}]`,
isArray: (v) => getType('Array')(v),
isObject: (v) => getType('Object')(v),
isFunction: (v) => getType('Function')(v),
}
// 解析promise,这里将会处理返回的promise或者其它情况下promise的状态让其直接变为完成状态并将参数值传入到下一个then
const resolvePromise = (promise2, x, resolve, reject) => {
let caller = false // 定义一个开关,为了让promise的状态一旦确定则不能再做修改
// 如果promise是它自己,避免自己等待自己,直接抛错
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<Promise>')
)
}
// 如果x是对象或者是一个函数的时候 那么它可能是一个promise,接下来将进一步解析。 这里是为了兼容第三方promise库,例如:q es6-promise
if ((x && isObject(x)) || isFunction(x)) {
try {
const then = x.then
// 确定then是一个函数的时候,那么肯定是一个promise
if (isFunction(then)) {
// 执行then函数
then.call(
x,
y => {
if (caller) return null
caller = true
// 递归解析,直到不是一个promise
resolvePromise(promise2, y, resolve, reject)
},
e => {
if (caller) return null
caller = true
// 如果发生错误,将直接变为拒绝状态并返回错误信息
reject(e)
}
)
} else {
// 如果不是一个promise,则直接将其状态变为完成并返回其值
resolve(x)
}
} catch (err) {
if (caller) return null
caller = true
// 发生错误这里直接将状态变为拒绝并返回错误信息
reject(err)
}
} else {
// 当x是一个普通值,那么将直接变为完成状态,并返回其值
resolve(x)
}
}
// 专门用来处理then的onFulfilled Or onRejected 回调
const onFulfilledOrOnRejectedHandler = (
promise2,
onFulfilledOrOnRejectedCallBack,
resolve,
reject,
value
) => {
// 此处的定时器为了等待Promise的实例完成
setTimeout(() => {
try {
// 执行then的resolve or reject函数并传入其值,通过一个变量x去拿到当前resolve执行后的返回值
const x = onFulfilledOrOnRejectedCallBack(value)
// 解析then的resolve or reject执行,如果返回一个promise或者其它值情况的处理
resolvePromise(promise2, x, resolve, reject)
} catch (err) {
// 如果返回发生错误,则直接reject
reject(err)
}
}, 0)
}
module.exports = {
PENDING,
FULFILLED,
REJECTED,
isArray,
isObject,
isFunction,
onFulfilledOrOnRejectedHandler
}
主文件 promise.js
const {
PENDING,
FULFILLED,
REJECTED,
isArray,
isObject,
isFunction,
onFulfilledOrOnRejectedHandler
} = require('./utils')
class Promise {
constructor(executor) {
this.status = PENDING
this.doneValue = undefined // 同步executor执行后,保存resolve函数参数值
this.resason = undefined // 同步executor执行后,保存reject函数的参数值
// 发布订阅模式。then方法执行时如发现状态未变,则订阅then方法执行的 完成 Or 拒绝 回调
this.doneCallbacks = []
this.failCallbacks = []
const resolve = (doneValue) => {
// 如果值是一个promise
if (doneValue instanceof Promise) {
// 将递归解析resolve中的参数直到不是一个promise对象
return doneValue.then(resolve, reject)
}
// 判断只有是等待状态的时候才进行成功处理,为了一旦状态发生改变将不会再改变状态
if (this.status === PENDING) {
this.status = FULFILLED
this.doneValue = doneValue
// 执行then方法的resolve订阅回调
this.doneCallbacks.forEach((fn) => fn())
}
}
const reject = (resason) => {
// 判断只有是等待状态的时候才进行拒绝处理,为了一旦状态发生改变将不会再改变状态
if (this.status === PENDING) {
this.status = REJECTED
this.resason = resason
// 执行then方法的reject订阅回调
this.failCallbacks.forEach((fn) => fn())
}
}
// 异常处理,一旦发生错误直接将状态变为拒绝并返回错误信息
try {
// 同步执行 executor promise的回调
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
// 内部定时器的作用是为了等待Promise的实例完成再执行
then(onFulfilled, onRejected) {
// 如果 onFulfilled Or onRejected 不是函数,则将其忽略,默认赋值一个函数返回其值,为了让值往下穿透
onFulfilled = isFunction(onFulfilled) ? onFulfilled : v => v
onRejected = isFunction(onRejected) ? onRejected : (err) => { throw err }
// then的执行必须返回一个新的promise,形成无限链式调用(也就是形成递归)
const promise2 = new Promise((resolve, reject) => {
let value = ''
let onFulfilledOrOnRejectedCallBack = ''
// 如果状态已变成完成状态 则保存onFulfilled回调 并保存完成的donevalue
if (this.status === FULFILLED) {
onFulfilledOrOnRejectedCallBack = onFulfilled
value = this.doneValue
}
// 如果状态已变成完成状态 则保存onRejected回调 并保存拒绝的resason
if (this.status === REJECTED) {
onFulfilledOrOnRejectedCallBack = onRejected
value = this.resason
}
// 执行对应状态的 onFulfilled Or onRejected 并传入对应的value
if (isFunction(onFulfilledOrOnRejectedCallBack)) {
setTimeout(() => {
onFulfilledOrOnRejectedHandler(
promise2,
onFulfilledOrOnRejectedCallBack,
resolve,
reject,
value
)
}, 0)
}
// 如果状态不变
if (this.status === PENDING) {
// 订阅then的完成回调
this.doneCallbacks.push(() => {
setTimeout(() => {
onFulfilledOrOnRejectedHandler(
promise2,
onFulfilled,
resolve,
reject,
this.doneValue
)
}, 0)
})
// 订阅then的拒绝回调
this.failCallbacks.push(() => {
setTimeout(() => {
onFulfilledOrOnRejectedHandler(
promise2,
onRejected,
resolve,
reject,
this.resason
)
}, 0)
})
}
})
return promise2
}
// catch的回调利用then方法的实现
catch(failCallback) {
return this.then(null, failCallback)
}
// finally 是无论如何都会执行的
// 如果返回一个promise,那么将会等待这个promise执行完毕
finally(callback) {
return this.then(
x => Promise.resolve(callback()).then(() => x),
e =>
Promise.reject(callback()).then(() => {
throw e
})
)
}
// resolve 的静态方法
static resolve(v) {
return new Promise((resolve) => {
resolve(v)
})
}
// reject 的静态方法
static reject(err) {
return new Promise((resolve, reject) => {
reject(err)
})
}
static all(promises) {
// 看一下进来的参数是不是一个数组
promises = isArray(promises) ? promises : []
let fulfilledCount = 0 // 状态变完成的个数
let promisesLength = promises.length // 需要完成的个数
let results = new Array(promisesLength) // 设置结果数组长度
return new Promise((resolve, reject) => {
// 如果是个空数组,那么将直接变为完成状态,并传入空数组参数值
if (promisesLength === 0) return resolve([])
// 遍历数组中的promise
promises.forEach((promise, index) => {
// 判断是不是一个promise
if (isObject(promise) && isFunction(promise.then)) {
promise.then(
(value) => {
// 向结果数组中存入 对应返回数据值
results[index] = value
// 当等于了需完成的个数,说明已全部都处理完了,那么就直接将状态变为完成,返回最终数据
if (++fulfilledCount === promisesLength) resolve(results)
},
(err) => reject(err) // 只要一个发生错误,那么直接变为失败,并返回失败原因
)
} else {
// 如果不是一个promise,将直接存值
results[index] = promise
if (++fulfilledCount === promisesLength) resolve(results)
}
})
})
}
// 看谁快
static race(promises) {
promises = isArray(promises) ? promises.filter(item => isObject(item) && isFunction(item.then)) : []
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(
(value) => resolve(value),
(err) => reject(err)
)
})
})
}
}
// 延迟执行,这个主要用于promise A+规范跑测使用
Promise.defer = Promise.deferred = () => {
let dfd = {}
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve
dfd.reject = reject
})
return dfd
}
module.exports = Promise
结语
以上就是全部的代码了,代码不是很多,Promise A+规范主要在于then方法,其它辅助方法都比较容易实现。
下面是这个源码的仓库地址,如果想直接测试一下可以拉下来跑一跑
扫码关注后,回复“资源”免费领取全套视频教程
2
发表评论(共0条评论)