ES6之手写Promise后续

77 阅读3分钟

ES6之手写Promise后续

/**
     * 
     * @param {Function} onRejected 失败的回调函数
     * @returns 
     */
    catch(onRejected) {
        return this.then(null, onRejected);
    }
    /**
     * 不论传什么函数,都会成功
     * @param {Function} onSettled 
     */
    finally(onSettled) {
        return this.then((data)=>{
            onSettled();
            return data;
        }, (reason)=>{
            onSettled();
            throw reason;
        })
    }

我们想要实现 catch ,可以直接套用 then 方法,只需要将第一个参数设为 null ,finally 方法是不论传递的函数是什么都会返回之前的结果,并且成功执行。除了在函数中出现报错,会把错误的结果返回。所以可以直接返回一个 Promise ,返回相关的数据。所以可以在返回的 then 里面套两个函数,都调用函数,然后将上一个结果和错误返回,不返回 finally 的数据。

/**
     * 返回一个Promise对象
     * 如果是原来的Promise对象,直接返回
     * 如果是PromiseLike,手动处理,返回和前面一样的状态
     * 否则返回成功结果
     * @param {any} data 
     */
    static resolve(data) {
        if(data instanceof MyPromise){
            return data;
        }
        return new MyPromise((resolve, reject) => {
            if(isPromise(data)){
                data.then(resolve, reject);
            }else{
                resolve(data);
            }
        });
    }
    /**
     * 直接返回失败的Promise    
     * @param {any} reason 
     * @returns 
     */
    static reject(reason) {
        return new MyPromise((resolve, reject) => {
            reject(reason);
        });
    }

官方对 resolve 是这么规定的。如果是传递一个 Promise ,则直接返回,如果传递一个类似于 Promise 的函数,先判断它是否满足 A+ 规范,如果满足则返回 then 的结果。否则返回一个成功的结果。对于 reject ,直接返回一个失败的结果。

/**
     * 静态方法,只有全部成功才成功,返回有顺序的结果
     * 如果失败,返回失败的第一个原因
     * @param {iterator} proms 
     * @returns 
     */
    static all(proms) {
        return new MyPromise((resolve, reject) => {
            try {
                let count = 0;//总个数
                let fulfilledCount = 0 //成功个数
                const results = [];//最后结果
                for (const p of proms) {
                    let i = count;
                    // console.log(i);
                    count++;
                    MyPromise.resolve(p).then(data => {
                        fulfilledCount++;
                        results[i] = data;
                        if (fulfilledCount === count) {
                            resolve(results);
                            console.log(results, 'results')
                        }
                    }, reject);
                }
                if(count === 0){
                    resolve(results);
                }
            } catch (error) {
                reject(error);
                console.error(error);
            }
        });
    }

all 方法只要有一个失败则都会失败,我们可以定义一个总个数和成功个数,如果相等就表示成功返回结果,如果失败就返回失败的原因。因为参入的是迭代器,不一定支持索引能使用for循环,所以使用forof循环。同时为了保持数组内原始的顺序,需要将索引对应的结果提前保存。如果传入的是一个空数组,则直接返回空数组。

/**
     * 不管成功还是失败都会返回所有的结果
     * @param {iterator} proms 
     */
    static allSettled(proms) {
        const ps = [];//存放所有的promise
        for (const p of proms) {
            ps.push(MyPromise.resolve(p).then((value) => ({
                status: FULFILLED,
                value,
            }), (reason) => ({
                status: REJECTED,
                reason,
            })))
        }
        return MyPromise.all(ps);
    }

我们可以利用 all 方法,只需要一个完全成功的数组。如果数组的每一项成功和失败我们都去输出结果,每一项都是成功的,这时将结果传给 all 方法,就可以返回所有的有顺序的结果。

/**
     * 只要有一个先有结果,就返回这个结果
     * @param {iterator} proms
     */
    static race(proms) {
        return new MyPromise((resolve, reject) => {
            for (const p of proms) {
                MyPromise.resolve(p).then(resolve, reject);
            }
        });
    }

可以直接调用 then 方法,看是否成功还是失败。这个过程只会执行一次,后续不会再继续进行。