美文网首页
手写 Promise

手写 Promise

作者: 欢欣的膜笛 | 来源:发表于2021-04-20 15:38 被阅读0次

简版

function myPromise(constructor) {
    let self = this;
    self.status = 'pending' // 定义状态改变前的初始状态
    self.value = undefined; // 定义状态为resolved的时候的状态
    self.reason = undefined; // 定义状态为rejected的时候的状态

    // 存储回调函数
    self.onFulfilledCallbacks = [];
    self.onRejectedCallbacks = [];

    function resolve(value) {
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved';

            self.onFulfilledCallbacks.forEach(function(fulfilledCallback) {
                fulfilledCallback();
            });
        }
    }

    function reject(reason) {
        if (self.status === 'pending') {
            self.reason = reason;
            self.status = 'rejected';

            self.onRejectedCallbacks.forEach(function(rejectedCallback) {
                rejectedCallback();
            });
        }
    }

    // 捕获构造异常 
    try {
        constructor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

myPromise.prototype.then = function(onFullfilled, onRejected) {
    let self = this;
    switch (self.status) {
        case 'resolved':
            onFullfilled(self.value);
            break;
        case 'rejected':
            onRejected(self.reason);
            break;
        case 'pending':
            self.onFulfilledCallbacks.push(() => {
                onFullfilled(self.value);
            });
            self.onRejectedCallbacks.push(() => {
                onRejected(self.reason);
            });
            break;
        default:
    }
}

new myPromise((resolve) => {
    console.log(1);
    setTimeout(() => {
        console.log(2);
        resolve(3)
    }, 2000);
}).then(value => console.log(value))

new myPromise((resolve) => {
    console.log(4);
    resolve(5)
}).then(value => console.log(value))

复杂版

/**
 * 用来处理then方法返回结果包装成promise 方便链式调用
 * @param {*} promise2 then方法执行产生的promise 方便链式调用
 * @param {*} x then方法执行完成功回调或者失败回调后的result
 * @param {*} resolve 返回的promise的resolve方法 用来更改promise最后的状态
 * @param {*} reject 返回的promise的reject方法 用来更改promise最后的状态
 */
 function resolvePromise(promise2, x, resolve, reject) {
    // 首先判断x和promise2是否是同一引用。如果是,那么就用一个类型错误作为Promise2的失败原因reject
    if (promise2 === x) return reject(new TypeError('循环引用了!'));
    // called 用来记录promise2的状态改变,一旦发生改变了 就不允许 再改成其他状态
    let called;
    if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
        // 如果x是一个对象或者函数 那么他就有可能是promise 需要注意 null typeof也是 object 所以需要排除掉
        // 先获得x中的then 如果这一步发生异常了,那么就直接把异常原因reject掉
        try {
            let then = x.then; // 防止别人瞎写报错
            if (typeof then === 'function') {
                // 如果then是个函数,那么就调用then,并且把成功回调和失败回调传进去;如果x是一个promise,并且最终状态时成功,那么就会执行成功的回调,如果失败就会执行失败的回调。如果失败了,就把失败的原因reject出去,做为promise2的失败原因,如果成功了那么成功的value值y,有可能仍然是promise,所以需要递归调用resolvePromise这个方法,直到返回值不是一个promise
                then.call(x, y => {
                    if (called) return;
                    called = true;
                    resolvePromise(promise2, y, resolve, reject)
                }, error => {
                    if (called) return;
                    called = true;
                    reject(error)
                })
            } else {
                resolve(x)
            }
        } catch (error) {
            if (called) return;
            called = true;
            reject(error)
        }
    } else {
        // 如果是一个普通值,那么就直接把x作为promise2的成功值value,resolve掉
        resolve(x)
    }
}


class MyPromise {
    static resolve(value) {
        return new MyPromise((resolve, reject) => {
            resolve(value)
        })
    }

    static reject(reason) {
        return new MyPromise((resolve, reject) => {
            reject(reason)
        })
    }

    // 全部
    static all(promises) {
        return new MyPromise((resolve, reject) => {
            let arr = [];
            let i = 0;

            function getResult(index, value) {
                arr[index] = value;
                if (++i == promises.length) {
                    resolve(arr)
                }
            }
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(data => {
                    getResult(i, data)
                }, reject)
            }
        })
    }

    // 第一个
    static race(promises) {
        return new MyPromise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                // resolve后,状态不能改变
                promises[i].then(resolve, reject)
            }
        })
    }

    static deferred() {
        const defer = {}
        defer.promise = new MyPromise((resolve, reject) => {
            defer.resolve = resolve
            defer.reject = reject
        })
        return defer
    }

    constructor(fn) {
        this.status = 'pending'; // 存储promise状态 pending fulfilled rejected.
        this.value = null; // 存储成功后的值
        this.reason = null; // 记录失败的原因
        this.fulfillCbs = []; // 异步时候收集成功回调
        this.rejectCbs = []; // 异步时候收集失败回调
        let resolve = value => {
            if (this.status === 'pending') {
                this.status = 'fulfilled'; // resolve的时候改变promise的状态
                this.value = value; // 修改成功的值
                // 异步执行后 调用resolve 再把存储的then中的成功回调函数执行一遍
                this.fulfillCbs.forEach(cb => {
                    cb()
                });
            }
        }
        let reject = reason => {
            if (this.status === 'pending') {
                this.status = 'rejected'; // reject的时候改变promise的状态
                this.reason = reason; // 修改失败的原因
                // 异步执行后 调用reject 再把存储的then中的失败回调函数执行一遍
                this.rejectCbs.forEach(cb => {
                    cb()
                });
            }
        }
        fn(resolve, reject);
    }

    catch (onRejected) {
        return this.then(null, onRejected)
    }

    then(onfulfilled, onrejected) {
        // onfulfilled then方法中的成功回调
        // onrejected then方法中的失败回调
        // 如果onfulfilled不是函数 那么就用默认的函数替代 以便达到值穿透
        onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : val => val;
        // 如果onrejected不是函数 那么就用默认的函数替代 以便达到值穿透
        onrejected = typeof onrejected === 'function' ? onrejected : err => {
            throw err
        }
        let promise2 = new MyPromise((resolve, reject) => {
            if (this.status === 'fulfilled') {
                // 加入setTimeout 模拟异步
                // 如果调用then的时候promise的状态已经变成了fulfilled,那么就调用成功回调,并且传递参数为成功的value
                setTimeout(() => {
                    // 如果执行回调发生了异常 那么就用这个异常作为promise2的失败原因
                    try {
                        // x 是执行成功回调的结果
                        let x = onfulfilled(this.value);
                        // 调用resolvePromise函数,根据x的值,来决定promise2的状态
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }

            if (this.status === 'rejected') {
                // 加入setTimeout 模拟异步
                // 如果调用then的时候promise 的状态已经变成了rejected 那么就调用失败回调 并且传递参数为 失败的reason
                setTimeout(() => {
                    // 如果执行回调发生了异常 那么就用这个异常作为promise2的失败原因
                    try {
                        // x 是执行失败回调的结果
                        let x = onrejected(this.reason);
                        // 调用resolvePromise函数,根据x的值,来决定promise2的状态
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (error) {
                        reject(error)
                    }
                }, 0)
            }

            if (this.status === 'pending') {
                // 如果调用then的时候,promise的状态还是pending,说明promsie执行器内部的resolve或者reject是异步执行的。那么就需要先把then方法中的成功回调和失败回调存储起来,等待promise的状态改成fulfilled或者rejected时候再按顺序执行相关回调
                this.fulfillCbs.push(() => {
                    // setTimeout模拟异步
                    setTimeout(() => {
                        // 如果执行回调发生了异常 那么就用这个异常作为promise2的失败原因
                        try {
                            // x 是执行成功回调的结果
                            let x = onfulfilled(this.value)
                            // 调用resolvePromise函数 根据x的值 来决定promise2的状态
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })

                this.rejectCbs.push(() => {
                    // setTimeout模拟异步
                    setTimeout(() => {
                        // 如果执行回调发生了异常 那么就用这个异常作为promise2的失败原因
                        try {
                            // x 是执行失败回调的结果
                            let x = onrejected(this.reason)
                            // 调用resolvePromise函数 根据x的值 来决定promise2的状态
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (error) {
                            reject(error)
                        }
                    }, 0)
                })
            }
        })
        return promise2;
    }
}


let promise = new MyPromise((resolve, reject) => {
    console.log('promise'); // 1:promise
    setTimeout(() => {
        console.log('执行 promise'); // 7:执行 promise
        resolve('hello ')
    }, 2000)
}).then(data => {
    console.log(data); // 8:hello
    return data + ' world'
}).then(res => {
    console.log(res) // 9:hello  world
})

const p1 = new MyPromise((resolve, reject) => {
    console.log('p1'); // 2:p1
    resolve(1);
});

const p2 = new MyPromise((resolve, reject) => {
    console.log('p2'); // 3:p2
    setTimeout(() => {
        console.log('执行 p2');  // 6:执行 p2
        resolve(2);
    }, 1000)
});

const p3 = new MyPromise((resolve, reject) => {
    console.log('p3');  // 4:p3
    setTimeout(() => {
        console.log('执行 p3'); // 10:执行 p3
        resolve(3);
    }, 3000)
});

MyPromise.race([p1, p2, p3]).then(data => {
    console.log(data); // 5:1
}, err => {
    console.log(err);
});

MyPromise.all([p1, p2, p3]).then(data => {
    console.log(data); // 11:[1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
    console.log(err);
});

module.exports = MyPromise

相关文章

  • 手写Promise

    手写 Promise 我们会通过手写一个符合 Promise/A+ 规范的 Promise 来深入理解它,并且手写...

  • 手写 Promise 系列 --- 3

    在前两篇(手写 Promise 系列 --- 1)和(手写 Promise 系列 ---2) 中,达成了3个目标 ...

  • 手写Promise

    $ 正常的promise用法   $ 手写的Promise   # 测试可行性

  • 手写promise

    手写promise 带大家手写一个 promis。在手写之前我会先简单介绍一下为什么要使用promise、prom...

  • 纯手写实现自己的nodejs promise 库

    纯手写实现自己的nodejs promise 库什么是Promise?promise 链Async/Await后续...

  • 手写基础 promise

    1. 前言 玩下吧 手写 promise,看看能写成啥样 2. promise 基础结构 3. 手写`promi...

  • 手写 Promise

    一、Promise 是一个异步操作返回的对象,用来传递异步操作的消息。 Promise 介绍和使用详见: 认识并使...

  • 手写Promise

  • 手写Promise

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。 这篇博客有关于P...

  • 手写promise

    本章节纯粹是对promise手写实现。如果不了解promise自行了解再来学习本章知识。promise初体验首先,...

网友评论

      本文标题:手写 Promise

      本文链接:https://www.haomeiwen.com/subject/mjawlltx.html