手动实现promise

67 阅读7分钟

1、第一步

  • 1.使用promise的时候,接收一个函数类型的参数executor,executor又接收resolve回调函数和reject回调函数。(因为resolve和reject是在executor函数里面去执行的,所以在executor函数中拿不到上面的回调函数,需要通过bind去改变他们的this指向为myPromise。)
  • 2.通过状态来控制,当我们多次执行resolve和reject的时候,只以第一次执行为准。
  • 3.执行resolve和reject回调函数的时候,是需要接受参数的,而且在.then中也可以拿到。
class myPromise{
    constructor(executor){
        this.state = 'pending'; // 2.等待态
        this.result = null; // 3.
        this.reason = null; // 3.
        executor(this.resolve.bind(this),this.reject.bind(this))
    }
    resolve(result){ // 3.
        // 2.
        if(this.state==='pending'){
            this.state = 'fulfilled';
            this.result = result; // 3.
        }
    }
    reject(result){ // 3.
        // 2.
        if(this.state==='pending'){
            this.state = 'rejected';
            this.reason = reason; // 3.
        }
    }
}

2、第二步

.then 接收成功和失败两个回调函数

  • 1.通过状态机制来控制成功和失败两个回调函数的执行时机
  • 2.进行容错处理
  • 3.执行resolve和reject回调函数需要等待状态变更后才去执行,需要通过setTimeout套一下模拟异步。
class myPromise{
    constructor(executor){
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        executor(this.resolve.bind(this),this.reject.bind(this))
    }
    resolve(result){
        if(this.state==='pending'){
            this.state = 'fulfilled';
            this.result = result;
        }
    }
    reject(result){
        if(this.state==='pending'){
            this.state = 'rejected';
            this.reason = reason;
        }
    }

    then(onFulfilled,onRejected){
        // 2.
        onFulfilled = typeof onFulfilled === 'function'?onFulfilled:value =>value;
        onRejected = typeof onRejected === 'function'?onRejected:reason =>{
            throw reason
        }

        // 1.
        if(this.state === 'fulfilled'){
            // 3.
            setTimeout(()=>{
                onFulfilled(this.result)
            })
        }
        if(this.state === 'rejected'){
            setTimeout(()=>{
                onRejected(this.reason)
            })
        }

    }
}

3、第三步

在promise中执行回调函数是异步执行,在.then中执行回调函数也是异步执行,由于都是异步执行,无法确定谁先执行,所以需要对其进行限制

  • 1.有一种情况是在执行.then的时候状态依然是pending,所以需要对pending状态进行处理,否则会出现程序报错
  • 2.当状态是pending的时候,将成功或失败的回调函数存储起来,通过数组存储
  • 3.当在执行pending的时候,需要将对应的成功或失败回调函数 push 到对应的数组中
  • 4.在执行resolve和reject的时候,将其遍历执行(保证状态变更后执行)
class myPromise{
    constructor(executor){
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        this.onFulfilledCallbacks = []; //2.
        this.onRejectedCallbacks = []; //2.
        executor(this.resolve.bind(this),this.reject.bind(this))
    }
    resolve(result){
        if(this.state==='pending'){
            this.state = 'fulfilled';
            this.result = result;
            // 4.
            this.onFulfilledCallbacks.forEach(callback=>{
                callback(result)
            })
        }
    }
    reject(result){
        if(this.state==='pending'){
            this.state = 'rejected';
            this.reason = reason;
            // 4.
            this.onRejectedCallbacks.forEach(callback=>{
                callback(reason)
            })
        }
    }
    then(onFulfilled,onRejected){
        onFulfilled = typeof onFulfilled === 'function'?onFulfilled:value =>value;
        onRejected = typeof onRejected === 'function'?onRejected:reason =>{
            throw reason
        }
        if(this.state === 'fulfilled'){
            setTimeout(()=>{
                onFulfilled(this.result)
            })
        }
        else if(this.state === 'rejected'){
            setTimeout(()=>{
                onRejected(this.reason)
            })
        }


        else if(this.state === 'pending'){ // 1.

            // 3.
            this.onFulfilledCallbacks.push(()=>{
                setTimeout(()=>{
                    onFulfilled(this.result)
                })
            })
            // 3.
            this.onRejectedCallbacks.push(()=>{
                setTimeout(()=>{
                    onRejected(this.reason)
                })
            })
        }
    }
}

4、第四步

实现.then的链式调用

  • 需要定义promise2,返回promise2。
class myPromise {
    constructor(executor) {
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        executor(this.resolve.bind(this), this.reject.bind(this))
    }
    resolve(result) {
        if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.result = result;
            this.onFulfilledCallbacks.forEach(callback => {
                callback(result)
            })
        }
    }
    reject(result) {
        if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(callback => {
                callback(reason)
            })
        }
    }
    then(onFulfilled, onRejected) {
        // 1.
        let promise2 = new myPromise((resolve, reject) => {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
            onRejected = typeof onRejected === 'function' ? onRejected : reason => {
                throw reason
            }
            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    onFulfilled(this.result)
                })
            }
            else if (this.state === 'rejected') {
                setTimeout(() => {
                    onRejected(this.reason)
                })
            }
            else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        onFulfilled(this.result)
                    })
                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        onRejected(this.reason)
                    })
                })
            }
        })
        return promise2; // 1.
    }
}

5、第五步

为了应对.then的返回值出现的多种情况,封装一个 resolvePromise 函数对其进行处理

  • 1.所以我们需要将回调函数的值复制给 x ,然后将 x 作为参数传入 resolvePromise 中去做处理,
  • 2.因为我们需要对 x 和 promise2 做比对,所以它接收 promise2 为参数,所以它一共接收4个参数(Promise2、x 以及 promise2 的成功回调和失败回调的函数,我们都做一样的处理。
  • 3.这时候我们需要用try catch的方式来捕获异常,如果是异常了就直接抛出错误。
  • 4.在执行回调函数的时候,我们也要用try catch的方式,如果执行异常了,直接执行this.reject来抛出异常
class myPromise {
    constructor(executor) {
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];

        // 4.
        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch{
            this.reject(error)
        }
    }
    resolve(result) {
        if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.result = result;
            this.onFulfilledCallbacks.forEach(callback => {
                callback(result)
            })
        }
    }
    reject(result) {
        if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(callback => {
                callback(reason)
            })
        }
    }
    then(onFulfilled, onRejected) {
        let promise2 = new myPromise((resolve, reject) => {
            onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
            onRejected = typeof onRejected === 'function' ? onRejected : reason => {
                throw reason
            }
            if (this.state === 'fulfilled') {
                setTimeout(() => {

                    // 3.
                    try {
                        let x = onFulfilled(this.result); // 1.
                        resolvePromise(promise2, x, resolve, reject); // 2.

                    } catch (e){
                        this.reject(e)
                    }

                })
            }
            else if (this.state === 'rejected') {
                setTimeout(() => {

                    // 3.
                    try {
                        let x = onRejected(this.reason); // 1.
                        resolvePromise(promise2, x, resolve, reject); // 2.

                    } catch (e) {
                        this.reject(e)
                    }

                })
            }
            else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {

                        // 3.
                        try {
                            let x = onFulfilled(this.result); //1.
                            resolvePromise(promise2, x, resolve, reject); // 2.
                        } catch (e) {
                            this.reject(e)
                        }

                    })
                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {

                        // 3.
                        try {
                            let x = onRejected(this.reason); // 1.
                            resolvePromise(promise2, x, resolve, reject); // 2.
                        } catch (e) {
                            this.reject(e)
                        }

                    })
                })
            }
        })
        return promise2;
    }
}

6、第六步

回调函数它们的返回值需要传入resolvePromise中做单独的处理

  • 1.这时then中传入的回调函数不是函数类型的话,要直接返回值
  • 2.然后上面判断是不是函数的兼容处理就不需要了。
class myPromise {
    constructor(executor) {
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];

        try {
            executor(this.resolve.bind(this), this.reject.bind(this))
        } catch {
            this.reject(error)
        }
    }
    resolve(result) {
        if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.result = result;
            this.onFulfilledCallbacks.forEach(callback => {
                callback(result)
            })
        }
    }
    reject(result) {
        if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(callback => {
                callback(reason)
            })
        }
    }

    then(onFulfilled, onRejected) {
        let promise2 = new myPromise((resolve, reject) => {

            // 容错处理 2.
            // onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
            // onRejected = typeof onRejected === 'function' ? onRejected : reason => {
            //     throw reason
            // }

            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        // 1.
                        if (typeof onFulfilled !== 'function') {
                            resolve(this.result)
                        } else {
                            let x = onFulfilled(this.result);
                            resolvePromise(promise2, x, resolve, reject);
                        }

                    } catch (e) {
                        this.reject(e)
                    }

                })
            }
            else if (this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        // 1.
                        if (typeof onFulfilled !== 'function') {
                            resolve(this.reason)
                        } else {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        }

                    } catch (e) {
                        this.reject(e)
                    }

                })
            }
            else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            // 1.
                            if (typeof onFulfilled !== 'function') {
                                resolve(this.result)
                            } else {
                                let x = onFulfilled(this.result);
                                resolvePromise(promise2, x, resolve, reject);
                            }

                        } catch (e) {
                            this.reject(e)
                        }

                    })
                })
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            // 1.
                            if (typeof onFulfilled !== 'function') {
                                resolve(this.result)
                            } else {
                                let x = onRejected(this.reason);
                                resolvePromise(promise2, x, resolve, reject);
                            }

                        } catch (e) {
                            this.reject(e)
                        }

                    })
                })
            }
        })
        return promise2;
    }
}

7、第七步

⭐️ 封装resolvePromise方法:(为了解决 .then 的返回值可能有多种类型:a.返回的是promise2;b.返回一个A+规范promise对象;(例如:我们手写的prmise);c.返回其他规范的promise对象;(返回thenable对象函数,不管是什么规范,它们都支持then属性);d.返回普通的值。)

  • 1.首次我们判断 x 和 promise2 是不是指向一个对象,如果指向一个对象的话,就会陷入死循环,所以我们要抛出异常。
  • 2.接下来我们判断 x 是不是符合A+规范的promise,如果是的话,我们就在then中拿到返回值,因为它的返回值有可能依然是promise对象,所以我们要传入resolvePromise中做递归处理。
  • 3.接下来我们判断它是不是符合其他规范的promise,如何判断其他规范的promise? 首先要判断x是否为对象或函数,其次判断x.then是否为函数,如果都是的话,它就是符合其他规范的promise.所以我们首先判断它是不是对象或函数,如果是的话,我们就将x.then赋值给then,接着我们看then是不是函数类型,如果是的话,我们就将它的this指向为x,然后拿到它的返回值y值传入resolvePromise函数中做递归处理,当发生异常的时候直接抛出异常,
  • 4.而且我们注意到,其他规范的promise有可能多次调用多次执行,所以我们需要给它们加锁,我们定义一个锁called为false,当执行then的时候,我们将状态变更为true,这样就保证了它们只执行一次。
function resolvePromise(promise2, x, resolve, reject) {
    // ⭐️ 1.
    if (x === promise2) {
        throw new TypeError('promise error')
    }

    // ⭐️ 2.
    if (x instanceof myPromise) {
        x.then(y => {
            resolvePromise(promise2, x, resolve, reject)
        }, reject);
    }

    // ⭐️ 3.
    else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        try {
            let then = x.then;
        } catch (e) {
            return reject(e);
        }
        if (typeof then === 'function') {
            let called = false; // 4.
            try {
                then.call(
                    x,
                    y => {
                        if (called) return; // 4.
                        called = true; // 4.
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (called) return;// 4.
                        called = true; // 4.
                        reject(r);
                    }
                )
            } catch (e) {
                if (called) return; // 4.
                called = true; // 4.
                reject(e)
            }

        } else {
            resolve(x);
        }
    } else {
        return resolve(x);
    }
}

第八步:完整版手写myPromise

// 2.封装 resolvePromise 方法
function resolvePromise(promise2, x, resolve, reject) {
    if (x === promise2) {
        throw new TypeError('promise error')
    }
    if (x instanceof myPromise) {
        x.then(y => {
            resolvePromise(promise2, x, resolve, reject)
        }, reject);
    }
    else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
        try {
            let then = x.then;
        } catch (e) {
            return reject(e);
        }
        if (typeof then === 'function') {
            let called = false;
            try {
                then.call(
                    x,
                    y => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject);
                    },
                    r => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                )
            } catch (e) {
                if (called) return;
                called = true;
                reject(e)
            }

        } else {
            resolve(x);
        }
    } else {
        return resolve(x);
    }
}


// 1.手写promise
class myPromise {
    constructor(executor) {
        this.state = 'pending';
        this.result = null;
        this.reason = null;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];
        try {
            executor(this.resolve.bind(this), this.reject.bind(this));
        } catch {
            this.reject(error)
        }
    }
    resolve(result) {
        if (this.state === 'pending') {
            this.state = 'fulfilled';
            this.result = result;
            this.onFulfilledCallbacks.forEach(callback => {
                callback(result)
            })
        }
    }
    reject(reason) {
        if (this.state === 'pending') {
            this.state = 'rejected';
            this.reason = reason;
            this.onRejectedCallbacks.forEach(callback => {
                callback(reason)
            })
        }
    }
    then(onFulfilled, onRejected) {
        let promise2 = new myPromise((resolve, reject) => {
            if (this.state === 'fulfilled') {
                setTimeout(() => {
                    try {
                        if (typeof onFulfilled !== 'function') {
                            resolve(this.result)
                        } else {
                            let x = onFulfilled(this.result);
                            resolvePromise(promise2, x, resolve, reject)
                        }

                    } catch (e) {
                        reject(e);
                    }


                })
            } else if (this.state === 'rejected') {
                setTimeout(() => {
                    try {
                        if (typeof onRejected !== 'function') {
                            resolve(this.reason)
                        } else {
                            let x = onRejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject)
                        }
                    } catch (e) {
                        reject(e);
                    }
                })
            } else if (this.state === 'pending') {
                this.onFulfilledCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onFulfilled !== 'function') {
                                resolve(this.result)
                            } else {
                                let x = onFulfilled(this.result);
                                resolvePromise(promise2, x, resolve, reject)
                            }
                        } catch (e) {
                            reject(e);
                        }

                    })
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            if (typeof onRejected !== 'function') {
                                resolve(this.reason)
                            } else {
                                let x = onRejected(this.reason);
                                resolvePromise(promise2, x, resolve, reject)
                            }
                        } catch (e) {
                            reject(e);
                        }
                    })
                })
            }
        })
        return promise2;
    }
}

// 3.调用封装的 myPromise
let p = new myPromise((resolve, reject) => {
    setTimeout(function () {
        // const num = Math.floor(Math.random()*100);
        const num = 6;
        if (num <= 50) {
            resolve(num);
        } else {
            reject('大于50');
        }
    }, 2000);
});

p.then((data) => {
    console.log('执行resolved:', data);
}, (err) => {
    console.log('执行rejected', err);
})