简单实现一个Promise

322 阅读4分钟

本文正在参加「金石计划」

前言:简单的实现一下Promise的核心。

初始结构:

在 new Promise() 实例的时候要传入一个函数作为参数,并且该函数参数会被自动执行;同时我们也需要向这个函数参数传入它自己的参数resolvereject;在原生的Promise里面,resolvereject都是以函数的形式执行的,所以我们可以使用类方法的形式来创建这两个函数。

class Pro{
    static PENDING='pending';static FULFILLED='fulfiled';static REJECTEd='rejected'  // 定义promise的三种状态
    constructor(fn){
        this.status=Pro.PENDING  // 初始化promise对象的状态
        fn(this.resolve,this.reject)  // promise对象中传入的函数
    }
    resolve(){};
    reject(){};
}

resolve与reject 函数

Promise对象的resolve函数与reject函数都是取决于Promise对象本身的状态:

  • pending:待定
  • fulfilled:成功
  • rejected:拒绝

并且resolve函数的功能是将Promise对象的状态从 pending 变成 fulfilled 状态;而reject函数的功能是将Promise对象的状态从 pending 变成 rejected 状态,同时这两个函数也接收参数,。所以完善这两个函数的功能:

class Pro {
    static PENDING = 'pending'; static FULFILLED = 'fulfiled'; static REJECTED = 'rejected'  // 定义promise的三种状态
    constructor(fn) {
        this.status = Pro.PENDING  // 初始化promise对象的状态
        this.result = null   // resolve与reject函数的参数
        fn(this.resolve.bind(this), this.reject.bind(this))  // 这里绑定this 因为在new出新实例之后再到外部环境执行这两个方法 this 丢失
    }
    resolve(result) {
        if (this.status === Pro.PENDING) {
            this.status = Pro.FULFILLED
            this.result=result
        }
    };
    reject(result) {
        if (this.status === Pro.PENDING) {
            this.status = Pro.REJECTED
            this.result=result
        }
    };
}

then方法

Promise.then()方法可接收两个参数,第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的,并且该方法只会执行某一个回调函数。当然在原生Promise的then方法里面如果传入的不是函数:如果忽略针对某个状态的回调函数参数,或者提供非函数 (nonfunction) 参数,那么 then 方法将会丢失关于该状态的回调函数信息,但是并不会产生错误。所以需要再判断。

  then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : () => { }  // 判断传入的是否为函数
        onRejected = typeof onRejected === 'function' ? onFulfilled : () => { }
        if (this.status === Pro.FULFILLED) {
            onFulfilled(this.result)
        }
        if (this.status === Pro.REJECTED) {
            onRejected(this.result)
        }
    }

异步

此时的Promise还不能实现异步的效果:

let p=new Pro((resolve,reject)=>{
    console.log(2);
    resolve('yes')
})

p.then(res=>{
    console.log(res);
})

console.log(3);
//1
//2
//yes
//3

此时的执行结果不会像正常的Promise一样先执行3 再执行.then 异步方法。所以我们可以在then方法里面通过设置setTimeout将其转化成异步仍任务。

 then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : () => { }
        onRejected = typeof onRejected === 'function' ? onFulfilled : () => { }
        if (this.status === Pro.FULFILLED) {
          setTimeout(()=>{
            onFulfilled(this.result)
          })
        }
        if (this.status === Pro.REJECTED) {
           setTimeout(()=>{
            onRejected(this.result)
           })
        }
    }

但是此时仍然存在着一个问题:

console.log(1);

let p=new Pro((resolve,reject)=>{
    console.log(2);
    setTimeout(()=>{
        resolve('yes')
        console.log(4);
    })
})

p.then(res=>{
    console.log(res);
},
res=>{console.log(res);})

console.log(3);
//1
//2
//3
//4

如果在Promsie里面添加setTimeout方法,那么此时resolve方法就不会被执行。那么导致这个结果产生的原因是什么?看看代码:执行了 打印 1 2 3 之后,此时轮到处理异步代码,然而此时Promise的状态还是pending,而我们没有处理pending的方法,所以此时resolve/reject方法就不执行。所以我们就要让then里面的函数稍后执行,让resolve执行完成之后再执行then方法。我们可以使用一个数组来保存函数。

class Pro {
    static PENDING = 'pending'; static FULFILLED = 'fulfiled'; static REJECTED = 'rejected'  // 定义promise的三种状态
    constructor(fn) {
        this.status = Pro.PENDING  // 初始化promise对象的状态
        this.resolveCallbacks = []   // 保存待执行函数
        this.rejectCallbacks = []
        this.result = null   // resolve与reject函数的参数
        try {
            fn(this.resolve.bind(this), this.reject.bind(this))  // 这里绑定this 因为在new出新实例之后再到外部环境执行这两个方法 this 丢失
        } catch (error) {
            this.reject(error)
        }
    }
    resolve(result) {
        setTimeout(() => {
            if (this.status === Pro.PENDING) {
                this.status = Pro.FULFILLED
                this.result = result
                this.resolveCallbacks.forEach(callback => {  // 遍历数组如果有待执行函数就执行
                    callback(result)
                })
            }
        })
    };
    reject(result) {
        setTimeout(() => {
            if (this.status === Pro.PENDING) {
                this.status = Pro.REJECTED
                this.result = result
                this.rejectCallbacks.forEach(callback => {
                    callback(result)
                })
            }
        })
    };
    then(onFulfilled, onRejected) {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : () => { }
        onRejected = typeof onRejected === 'function' ? onFulfilled : () => { }
        if (this.status === Pro.PENDING) {  // pending 状态
            this.resolveCallbacks.push(onFulfilled)
            this.rejectCallbacks.push(onRejected)
        }
        if (this.status === Pro.FULFILLED) {
            setTimeout(() => {
                onFulfilled(this.result)
            })
        }
        if (this.status === Pro.REJECTED) {
            setTimeout(() => {
                onRejected(this.result)
            })
        }
    }
}

链式

实现链式直接在then方法里面返回出一个新的Promise对象即可。

class Pro {
    static PENDING = 'pending'; static FULFILLED = 'fulfiled'; static REJECTED = 'rejected'  // 定义promise的三种状态
    constructor(fn) {
        this.status = Pro.PENDING  // 初始化promise对象的状态
        this.resolveCallbacks = []
        this.rejectCallbacks = []
        this.result = null   // resolve与reject函数的参数
        try {
            fn(this.resolve.bind(this), this.reject.bind(this))  // 这里绑定this 因为在new出新实例之后再到外部环境执行这两个方法 this 丢失
        } catch (error) {
            this.reject(error)
        }
    }
    resolve(result) {
        setTimeout(() => {
            if (this.status === Pro.PENDING) {
                this.status = Pro.FULFILLED
                this.result = result
                this.resolveCallbacks.forEach(callback => {
                    callback(result)
                })
            }
        })
    };
    reject(result) {
        setTimeout(() => {
            if (this.status === Pro.PENDING) {
                this.status = Pro.REJECTED
                this.result = result
                this.rejectCallbacks.forEach(callback => {
                    callback(result)
                })
            }
        })
    };
    then(onFulfilled, onRejected) {
        return new Pro((resolve, reject) => {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : () => { }
            onRejected = typeof onRejected === 'function' ? onFulfilled : () => { }
            if (this.status === Pro.PENDING) {
                this.resolveCallbacks.push(onFulfilled)
                this.rejectCallbacks.push(onRejected)
            }
            if (this.status === Pro.FULFILLED) {
                setTimeout(() => {
                    onFulfilled(this.result)
                })
            }
            if (this.status === Pro.REJECTED) {
                setTimeout(() => {
                    onRejected(this.result)
                })
            }
        })
    }
}

以上就简单的梳理了一下promise比较核心的一些功能。