手把手教你手写一个promise

204 阅读3分钟

Promise

说到promise,大家都不会陌生。现在面试基本都会遇到promise的问题,废话不多说,本篇就来一步步解析,带大家写一个自己的promise。

初始化项目

新建一个文件夹,来作为项目目录,在目录下创建两个文件

  • index.js (作为主程序
  • myPromise.js (写我们的promise类
mkdir promise-demo
cd promise-demo
touch index.js
touch myPromise.js

小伙伴们,我们的项目文件初始化工作就做好了,接下来,我们开始规划一下promise类,看看他会实现什么功能,这些功能又怎么对应的编写成类方法。

promise类

先上代码

// 定义各状态值
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECT = 'reject'

// myPromise是一个类 
class myPromise {
    // 构造方法中调用实例化时传入的执行器 并将两个原型方法传递给执行器
    constructor (exer) {
        // 为了捕获错误
        try {
            exer(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    // 初始化状态值为等待
    status = PENDING
    // 初始化成功和失败的值
    successData = undefined
    failReason = undefined
    successFunc = []
    failFunc = []
    // 使用箭头函数 this指向实例化后的myPromise实例对象
    resolve = (data) => {
        // 判断是否状态是PENDING 否则返回
        if (this.status !== PENDING) return
        this.status = FULFILLED
        this.successData = data
        // 循环调用
        while(this.successFunc.length) this.successFunc.shift()()
    }
    reject = (reason) => {
        // 判断是否状态是PENDING 否则返回
        if (this.status !== PENDING) return
        this.status = REJECT
        this.failReason = reason
        while(this.failFunc.length) this.failFunc.shift()()
    }
    then = (resolve, reject) => {
        // then可变参
        resolve = resolve ? resolve : value => value
        reject = reject ? reject : reason => { throw reason}
        // 每一个then之后都会返回一个myPromise对象 以进行链式调用
        let promise2 = new myPromise((successCallBack, failCallBack) => {
            // 立即执行的代码
            switch (this.status) {
                case FULFILLED:
                    // 如果已经触发了resolve 直接执行传入方法
                    // resolve(this.successData)
                    // 由于链式调用 这里会返回promise或者值或空 
                    // 我们需要在执行完resolve后按结果调用下一个then的resolve或reject,
                    // 也就是这个返回的promise的successCallBack,和failCallBack
                    setTimeout(()=> {
                        try{
                            let x = resolve(this.successData)
                            // 这个x就是执行完resolve后的返回
                            solvePromise(promise2, x, successCallBack, failCallBack)
                        } catch (error) {
                            failCallBack(error)
                        }
                    }, 0)
                    break;
                case REJECT:
                    setTimeout(()=> {
                        try{
                            let x = reject(this.failReason)
                            solvePromise(promise2, x, successCallBack, failCallBack)
                        } catch (error) {
                            failCallBack(error)
                        }
                    }, 0)
                    break;
                case PENDING:
                    // 如果是等待的状态 把方法存进数组 以进行多次调用
                    this.successFunc.push(() => {
                        setTimeout(()=> {
                            try{
                                let x = resolve(this.successData)
                                // 这个x就是执行完resolve后的返回
                                solvePromise(promise2, x, successCallBack, failCallBack)
                            } catch (error) {
                                failCallBack(error)
                            }
                        }, 0)
                    })
                    this.failFunc.push(() => {
                        setTimeout(()=> {
                            try{
                                let x = reject(this.failReason)
                                solvePromise(promise2, x, successCallBack, failCallBack)
                            } catch (error) {
                                failCallBack(error)
                            }
                        }, 0)
                    })
                default:
                    break;
            }
        })
        return promise2
    }
    catch (failCallBack) {
        this.then(undefined, failCallBack)
    }
    finally (cb) {
        return this.then(value => {
            cb()
            return value
        }, reason => {
            cb()
            throw reason
        })
    }
    static resolve (value) {
        if (value instanceof myPromise) return value
        return new myPromise(resolve => resolve(value))
    }
    static all = (array) => {
        let list = []
        let index = 0
        return new myPromise((resolve, reject) => {
            function addData  (key, value) {
                console.log(key, value)
                list[key] = value
                index++
                if (index === array.length) {
                    resolve(list)
                }
            }
            for (let i = 0; i< array.length; i++) {
                let pro = array[i]
                if (pro instanceof myPromise ) {
                    pro.then(value => addData(i, value))
                } else {
                    addData(i, pro)
                }
            }
        })
    }
}

function solvePromise (promise, x, resolve, reject) {
    if (promise === x) {
        return reject(new TypeError('哥们 这你咋还返回当前的promise呢'))
    }
    if (x instanceof myPromise) {
        // 如果是一个myPromise的返回 比如是一个ajax请求 调用它的then方法 
        // 并按实际执行的情况 调用返回的myPromise实例的successCallBack或failCallBack
        x.then(resolve, reject)
    } else {
        // 如果是值 直接执行resolve 如果是空 透传
        resolve(x)
    }
}

module.exports = myPromise

调用

let myPromise = require('./myPromise')

let process = new myPromise((resolve, reject) => {
})