手写Promise A+规范源码

196 阅读4分钟

一、核心实现

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function Promise (executor) {
    const self = this
    self.status = PENDING // promise的状态 分别是pending | fulfiled | rejected
    self.value = '' // 成功的值
    self.reason = '' //失败的原因
    self.onFulfiled = [] // 保存成功的回调
    self.onRejected = [] // 保存失败的回调

    function resolve (value) {
      if (self.status !== PENDING) return
      self.status = FULFILLED
      self.value = value
      self.onFulfiled.forEach(fn => fn())
    }

    function reject(reason) {
      if (self.status !== PENDING) return
      self.status = REJECTED
      self.reason = reason
      self.onRejected.forEach(fn => fn())
    }

    try {
        executor(resolve, reject)
    } catch (e) {
        reject(e)
    }
}

Promise.prototype.then = function (onFulfiled, onRejected) {
    onFulfiled = typeof onFulfiled === 'function'? onFulfiled : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
    const self = this
    const promise2 = new Promise((resolve, reject) => {
        // 如果fulfiled | rejected 则直接执行回调
        if (self.status === FULFILLED) {
            setTimeout(() => {
                try {
                    const x = onFulfiled(self.value)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })

        } else if(self.status === REJECTED) {
            setTimeout(() => {
                try {
                    const x = onRejected(self.reason)
                    resolvePromise(promise2, x, resolve, reject)
                } catch (e) {
                    reject(e)
                }
            })
        } else {
           self.onFulfiled.push(() => {
                setTimeout(() => {
                    try {
                        const x = onFulfiled(self.value)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
           })
            self.onRejected.push(() => {
                setTimeout(() => {
                    try {
                        const x = onRejected(self.reason)
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                })
            })
        }
    })
    return promise2
}

function resolvePromise(promise2, x, resolve, reject) {
    // 如果返回的值x就是promise2, 就是循环调用了
    if(promise2 === x) {
        reject(new TypeError('Chaining cycle'))
    }

    if (x && typeof x === 'object' || typeof x === 'function') {
        let called;
        try {
            const then = x.then
            if (typeof then === 'function') { // x是promise类型
                then.call(x, y => {
                    if (called) return
                    called = true
                    // 需要递归调用resolvePromise,防止y也循环调用了promise2,或者y也是一个promise对象
                    resolvePromise(promise2, y, resolve, reject)

                }, r => {
                    if (called) return
                    called = true
                    reject(r)
                })
            } else { // x是普通的对象
                if (called) return
                called = true
                resolve(x)
            }
        } catch (e) {
            if (called) return
            called = true
            reject(e)
        }
    } else {
        // x是普通类型的值
        resolve(x)
    }

}

二、其它方法

1. resolve 方法

功能分析

会返回一个由 value 来决定的 Promise 对象,value 有以下几种情况:

  1. value 本身就是promise对象,就直接返回该对象
  2. value 是一个 thenable 对象(即,带有 then 方法的对象),返回的promise对象最终状态由 then 方法执行决定
  3. value 是空、基本类型或者不带 then 方法的对象

功能实现

Promise.resolve = function (value) {
    // 传入的value,本身就是promise实例,就直接返回
    if (value instanceof Promise) return value
    return new Promise((resolve, reject) => {
        // 带有then方法的对象
        if (value && typeof value === 'object' && value.then === 'function' ) {
            setTimeout(() => {
                value.then(resolve, reject)
            })
        } else {
            // 普通值
            resolve(value)
        }
    })
}

测试一下

// 输出  1  3:1  2
Promise.resolve(new Promise((resolve, reject) => {
    console.log(1)
    resolve('1')
})).then(res => {
  console.log('3',res)
})
console.log('2')


// 输出 1 2
Promise.resolve(2).then(res => {
  console.log(res)
})
console.log('1')
//


// 输出 30
const p2 = Promise.resolve({
    then: (resolve, reject) => {
        resolve(30)
    }
})
p2.then(res => {
    console.log(res)
})

2. reject 方法

功能分析

返回一个状态失败的 Promise 对象,并将给定的失败信息传递给对应的处理方法

功能实现

Promise.reject = function (reason) {
    return new Promise((reolve, reject) => {
        reject(reson)
    })
}

3. Promise.prototype.catch

功能分析 用于指定出错时的回调,是特殊的 then 方法,catch 之后可以继续.then

功能实现

Promise.prototype.catch = function (onRejected) {
    this.then(null, onRejected)
}

**PS:**如果前面 then 方法中有 onRejected 回调,catch 方法是不会执行的

4. Promise.prototype.finally

功能分析 不管成功还是失败,都是执行 finally 中的内容,还可以继续后面的 then,并且将值原封不动的传递给后面的 then。

功能实现

Promise.prototype.finally = function (callBack) {
    return this.then(value => {
        return Promise.resolve(callBack()).then(() => {
            return value
        })
    }, err => {
        return Promise.reject(callBack()).then(() => {
            throw err;
        })
    })
}

PS: 主要是为了避免同样的语句需要在 then、catch 中各写一次的情况

5.Promise.all 方法

该方法接收一个 promise 的 iterable(PS: Array, Map, Set) 类型的输入,并且返回一个 Promise 实例

功能分析

  • 如果传入的参数是一个空的可迭代的对象,则返回一个已完成状态的 promise
  • 如果传入的参数不包含任何的 promise,则返回一个异步完成
  • 如果传入的参数中有一个 promise 失败,则直接返回失败的值
  • 如果传入的参数中的 promise 都成功了,则将结果按参数传入的顺序返回

功能实现

Promise.all = function (promises) {
    promises = Array.from(promises) // 将迭代对象转换为数组
    return new Promise((resolve, reject) => {
        let index = 0
        let result = []
        // promises 为空,返回一个已完成的状态
        if (promises.length === 0) {
            resolve(result)
        } else {
            function processValue (i, data) {
                result[i] = data
                if (++index === promises.length) {
                    resolve(result)
                }
            }
            for(let i = 0, len = promises.length; i < len; i++) {
                // promises[i] 可能是一个普通的
                Promise.resolve(promises[i]).then(res => {
                    processValue(i, res)
                }, err => {
                    reject(err)
                })
            }
        }

    })
}

6. Promise.race

方法返回一个 promise,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。

功能分析

  • 如果传入的参数数组是空,则返回的 promise 将永远为等待状态
  • 如果迭代包含一个或多个非承诺和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值

功能实现

Promise.race = function (promises) {
    promises = Array.from(promise)
    return new Promise ((resolve, reject) => {
        if (promises.length === 0) return
        for (let i = 0, len = promises.length; i < len; i++) {
            Promise.resolve(promises[i]).then(res => {
                resolve(res)
            }, err => {
                reject(err)
            })
        }
    })
}

三、参考