实现Promise
const PENDING = 'pending'
const RESOLVED = 'resolved'
const REJECTED = 'rejected'
function MyPromise(fn) {
const that = this
that.state = PENDING
that.value = null
that.resolvedCallbacks = []
that.rejectedCallbacks = []
}
- 一个 Promise 的当前状态必须为以下三种状态中的一种:
等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)
- ⼀开始 Promise 的状态应该是 pending
- value 变量⽤于保存 resolve 或者 reject 中传⼊的值
- resolvedCallbacks 和 rejectedCallbacks ⽤于保存 then 中的回调,因为当执⾏完 Promise 时状态可能还是等待 中,这时候应该把 then 中的回调保存起来⽤于状态改变时使 ⽤
resolve、reject
function resolve(value) {
if (that.state === PENDING) {
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value))
}
}
function reject(value) {
if (that.state === PENDING) {
that.state = REJECTED
that.value = value
that.rejectedCallbacks.map(cb => cb(that.value))
}
}
- ⾸先两个函数都得判断当前状态是否为等待中,因为规范规定 只有等待态才可以改变状态
- 将当前状态更改为对应状态,并且将传⼊的值赋值给 value
- 遍历回调数组并执⾏
Promise
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
then 函数
MyPromise.prototype.then = function(onFulfilled, onRejected) {
const that = this
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r
}
if (that.state === PENDING) {
that.resolvedCallbacks.push(onFulfilled) that.rejectedCallbacks.push(onRejected)
}
if (that.state === RESOLVED) {
onFulfilled(that.value)
}
if (that.state === REJECTED) {
onRejected(that.value)
}
}
- ⾸先判断两个参数是否为函数类型,因为这两个参数是可选参数
- 当参数不是函数类型时,需要创建⼀个函数赋值给对应的参 数,同时也实现了透传,⽐如如下代码
Promise.resolve(4).then().then((value) => console.log(value))
- 接下来就是⼀系列判断状态的逻辑,当状态不是等待态时,就 去执⾏相对应的函数。如果状态是等待态的话,就往回调函数 中 push 函数,⽐如如下代码就会进⼊等待态的逻辑
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1) }, 0)
}).then(value => {
console.log(value)
})
优化
resolve、reject
function resolve(value) {
if (value instanceof MyPromise) {
return value.then(resolve, reject)
}
setTimeout(() => {
if (that.state === PENDING)
{ that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value)) } }, 0)
}
function reject(value) {
setTimeout(() => {
if (that.state === PENDING) {
that.state = REJECTED
that.value = value that.rejectedCallbacks.map(cb => cb(that.value)) } }, 0)
}
- 对于 resolve 函数来说,⾸先需要判断传⼊的值是否为 Promise 类型
- 为了保证函数执⾏顺序,需要将两个函数体代码使⽤ setTimeout 包裹起来
then 函数
- 新增⼀个变量 promise2,因为每个 then 函数都需要返回⼀个新的 Promise 对 象,该变量⽤于保存新的返回对象,然后我们先来改造判断等待态的逻辑
if (that.state === PENDING) {
return (promise2 = new MyPromise((resolve, reject) => { that.resolvedCallbacks.push(() => {
try {
const x = onFulfilled(that.value)
resolutionProcedure(promise2, x, resolve, reject)} catch (r) {
reject(r)
} })
that.rejectedCallbacks.push(() => {
try {
const x = onRejected(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
})) }
- ⾸先我们返回了⼀个新的 Promise 对象,并在 Promise 中 传⼊了⼀个函数
- 函数的基本逻辑还是和之前⼀样,往回调数组中 push 函数
- 同样,在执⾏函数的过程中可能会遇到错误,所以使⽤了 try...catch 包裹
- 规范规定,执⾏ onFulfilled 或者 onRejected 函数时会 返回⼀个 x,并且执⾏ Promise 解决过程,这是为了不同的 Promise 都可以兼容使⽤,⽐如 JQuery 的 Promise 能兼容ES6 的 Promise
判断执⾏态的逻辑
if (that.state === RESOLVED) {
return (promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const x = onFulfilled(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) {
reject(reason) }
}) }))
}
兼容多种 Promise 的 resolutionProcedure 函数
function resolutionProcedure(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Error'))
}
}
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
then.call( x,y => {
if (called) return called = true
resolutionProcedure(promise2, y, resolve, reject)
},e => {
if (called) return called = true
reject(e) } )
} else {
resolve(x) }
} catch (e) {
if (called) return called = true
reject(e) } }
else {
resolve(x)
}
- 创建⼀个变量 called ⽤于判断是否已经调⽤过函数
- 然后判断 x 是否为对象或者函数,如果都不是的话,将 x 传⼊ resolve 中
- 如果 x 是对象或者函数的话,先把 x.then 赋值给 then,然 后判断 then 的类型,如果不是函数类型的话,就将 x 传⼊ resolve 中
- 如果 then 是函数类型的话,就将 x 作为函数的作⽤域 this 调⽤之,并且传递两个回调函数作为参数,第⼀个参数叫做 resolvePromise ,第⼆个参数叫做 rejectPromise,两 个回调函数都需要判断是否已经执⾏过函数,然后进⾏相应的 逻辑
- 以上代码在执⾏的过程中如果抛错了,将错误传⼊ reject 函 数中
网友评论