跟我一起来刷题(4)—— ES6实现手写Promise

458 阅读2分钟

promise简要介绍

promise是一种解决异步编程的解决方案,promise一个容器,里面保存着未来异步结束事件的值,promise某种意义上是一种对象结构,promise提供了很多的操作运算;如then等;

promise实现核心

1、 promise三个状态——pedding, resolve,reject; 从pedding转变为resolve; 从pedding转变为reject;状态转变了就不可逆; 2、 .then类似于一个promise的转换,管道通路;promise的一个传递和接通,核心点就是.then(上个promise的resolve,reject);就可以接通了;

实现细节

实例变量

  • this.state(描述promise状态)
  • this.data(描述promise异步获取到的值)
  • this.resolveCallBacks(promise成功事件回调队列)
  • this.rejectCallBacks的抽离;(promise失败事件回调)

原型上的方法

  • then;(1、分为三种状态来处理 —— pedding,resolve,reject; 2、then返回的一个promise; 3、拿到当前promise的值包在promise里面返回)
  • catch (1、就是.then(null, onReject));

静态方法:

  • all (接收一个promise数组,如果是成功状态:返回一个promise包装的所有成功状态的值;如果是失败,就返回reject)
  • race (接收一个promise数组, 返回最先改变的状态的某个promise)
  • resolve
const PEDDING = 'pedding';
const RESOLVE = 'resolve';
const REJECT = 'reject';
class MyPromise {
    constructor(fn) {
        this.state = PEDDING;
        this.data = null;
        this.resolveCallBacks = [];
        this.rejectCallBacks = [];
        const resolve = (value) => {
            if(this.state === PEDDING) {
                this.state = RESOLVE;
                this.data = value;
                this.resolveCallBacks.forEach(item => {
                    item(value);
                })
            }

        };
        const reject = (value) => {
            if(this.state === PEDDING) {
                this.state = REJECT;
                this.data = value;
                this.rejectCallBacks.forEach(item => {
                    item(value);
                })
            }

        }
        try {
            fn(resolve, reject);
        } catch(e) {
            reject(e);
        }
    }
    then(onResolve, onReject) {
        let promise = null;
        onResolve = typeof onResolve === 'function' ? onResolve : () => {};
        onReject = typeof onReject === 'function' ? onReject : () => {};
        if(this.state === RESOLVE) {
            return promise = new Promise((resolve, reject) => {
                try {
                    const v = onResolve(this.data);
                    if(v instanceof Promise) {
                        v.then(resolve, reject);
                    }
                    resolve(this.data)
                } catch(e) {
                    reject(e);
                }
            })
        } 
        if(this.state === REJECT) {
            return promise = new Promise((resolve, reject) => {
                try {
                    const v = onReject(this.data);
                    if(v instanceof Promise) {
                        v.then(resolve, reject);
                    }
                    reject(this.data);
                } catch(e) {
                    reject(e);
                }
            })
        }
        if(this.state === PEDDING) {
            return promise = new Promise((resolve,reject) => {
                this.resolveCallBacks.push((value) => {
                    try {
                        const v = onResolve(value);
                        if(v instanceof Promise) {
                            v.then(resolve, reject);
                        }
                    } catch(e) {
                        reject(e)
                    }
                })
                this.rejectCallBacks.push((value) => {
                    try {
                        const v = onReject(value);
                        if(v instanceof Promise) {
                            v.then(resolve, reject);
                        }
                    } catch(e) {
                        reject(e)
                    }
                })
            })
        }
    }

    catch(onRejct) {
        this.then(null,onRejct);
    }

    static resolve(value) {
        return new Promise((resolve) => {
            if(value instanceof Promise) {
                value.then(resolve);
            }
            resolve(value);
        })
    }

    static all(iterable) {
        if(Array.isArray(iterable)) {
            throw new Error('iterable need array');
        }
        return new Promise((resolve, reject) => {
            let totalCount = 0;
            let responseArr = [];
            iterable.forEach((promise,index) => {
                MyPromise.resolve(promise).then((value) => {
                    totalCount++;
                    responseArr[index] = value;
                    if(totalCount === iterable.length) {
                        resolve(responseArr);
                    }
                }, (reason) => {
                    reject(reason);
                })
            })
        })
    }

    static race(iterable) {
        if(Array.isArray(iterable)) {
            throw new Error('iterable need array');
        }
        return new Promise((resolve, reject) => {
            iterable.forEach((promise) => {
                MyPromise.resolve(promise).then(
                    value => {
                     resolve(value)
                    }, reason => {
                        reject(reason)
                    });
                })
        })
    }
}