Promise简洁版实现流程

目标:实现1.Promise的异步机制,2.then的链式调用

1.resolve和reject调用(同步)

// 等待中
const PENDING = 'pending';
// 成功
const RESOLVE = 'resolve';
// 失败
const REJECT = 'reject';
class MyPromise {
    constructor(execute) {
        execute(this.resolve, this.reject);
    }

    // 当前状态
    status = PENDING;
    // 成功的数据
    value = null;
    // 失败数据
    fail = null;

    resolve = value => {
        if (this.status === PENDING) {
            this.value = value;
            this.status = RESOLVE;
        }
    };

    reject = value => {
        if (this.status === PENDING) {
            this.fail = value;
            this.status = REJECT;
        }
    };

    then(onFuResolv, onFuReject) {
        // 容错处理,使then里面的参数可以选
        onFuResolv = typeof onFuResolv === 'function' ? onFuResolv : value => value;
        onFuReject = typeof onFuReject === 'function' ? onFuReject : value => new Error(this.fail);

        if (this.status === RESOLVE) {
            onFuResolv(this.value);
        } else if (this.status === REJECT) {
            onFuReject(this.fail);
        }
    }
}

module.exports = MyPromise;

// 测试
const p1 = new MyPromise((resolve, reject) => {
                resolve('成功');
                reject('失败');
            });

            p1.then(
                res => {
                    console.log('res', res);
                },
                e => {
                    console.log('e', e);
                }
            );
// res 成功

上面只支持同步调用,如果new MyPromise 里面有异步任务就不会有返回值:如

const p1 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    resolve('成功');
                }, 0);
            });
p1.then(res => {
  console.log('res', res); // 不会有返回结构  
  })

2.实现在 new MyPromise时如果异步调用 resolve 或 reject在then里面能拿到结果

因为在 then 里面 判断 status 是 PENDING 状态时,将未执行的方法添加到了数组里面,在 resolve 或 reject 执行时会循环调用 成功 或 失败 的回调函数,这就实现了另一个功能,多次 new MyPromise,不会产生冲突

class MyPromise {
    constructor(execute) {
        execute(this.resolve, this.reject);
    }

    // 当前状态
    status = PENDING;
    // 成功的数据
    value = null;
    // 失败数据
    fail = null;

    // 新增
    // 成功回调的集合
    onFuResolvCallback = [];
    // 失败回调的集合
    onFuRejectCallback = [];

    resolve = value => {
        if (this.status === PENDING) {
            this.value = value;
            this.status = RESOLVE;
            
            // 新增
            // 当 resolve 异步执行时 onFuResolvCallback有未执行的回调时
            while (this.onFuResolvCallback.length) {
                this.onFuResolvCallback.shift()(this.value);
            }
        }
    };

    reject = value => {
        if (this.status === PENDING) {
            this.fail = value;
            this.status = REJECT;

            // 新增
            // 当 reject 异步执行时 onFuResolvCallback有未执行的回调时
            while (this.onFuRejectCallback.length) {
                this.onFuRejectCallback.shift()(this.fail);
            }
        }
    };

    then(onFuResolv, onFuReject) {
        // 容错处理,使then里面的参数可以选
        onFuResolv = typeof onFuResolv === 'function' ? onFuResolv : value => value;
        onFuReject = typeof onFuReject === 'function' ? onFuReject : value => new Error(this.fail);

        if (this.status === RESOLVE) {
            onFuResolv(this.value);
        } else if (this.status === REJECT) {
            onFuReject(this.fail);
            // 新增
        } else if (this.status === PENDING) {
            this.onFuResolvCallback.push(onFuResolv);
            this.onFuRejectCallback.push(onFuReject);
        }
    }
}

// 测试
            const p1 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    resolve('成功');
                    // reject('失败');
                }, 50);
            });

            const p2 = new MyPromise((resolve, reject) => {
                setTimeout(() => {
                    // resolve('成功');
                    reject('失败');
                }, 1000);
            });

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

            p1.then(
                res => {},
                e => {
                    console.log('e', e);
                }
            );
// e 失败
// res 成功

3.使其支持链式调用及嵌套Promise

  1. 通过在then里面返回一个 MyPromise2 使其支持链式调用

  1. 在 RESOLVE,PENDING,PENDING三个状态里面添加对应的微任务,使其支持在then里面可以嵌套异步任务

  1. 通过 thenRetHandle 方法处理then返回的数据(重要)

    then(onFuResolv, onFuReject) {
        // 容错处理,使then里面的参数可以选
        onFuResolv = typeof onFuResolv === 'function' ? onFuResolv : value => value;
        onFuReject = typeof onFuReject === 'function' ? onFuReject : value => new Error(this.fail);

        // 返回一个新的 MyPromise 使其可以链式调用 then
        const MyPromise2 = new MyPromise((resolve, reject) => {
            // 成功的微任务
            const resolveMicrotask = () => {
                queueMicrotask(() => {
                    const x = onFuResolv(this.value);
                    thenRetHandle(MyPromise2, x, resolve, reject);
                });
            };

            // 失败的微任务
            const rejectMicrotask = () => {
                const x = onFuReject(this.fail);
                thenRetHandle(MyPromise2, x, resolve, reject);
            };

            if (this.status === RESOLVE) {
                resolveMicrotask();
            } else if (this.status === REJECT) {
                rejectMicrotask();
            } else if (this.status === PENDING) {
                queueMicrotask(() => {
                    this.onFuResolvCallback.push(resolveMicrotask);
                    this.onFuRejectCallback.push(rejectMicrotask);
                });
            }
        });

        return MyPromise2;
    }

// 每次 then 时返回值的处理(重要函数,用来处理then返回的数据)
function thenRetHandle(MyPromise2, x, resolve, reject) {
    // 防止重复调用
    if (x === MyPromise2) {
        return reject(new TypeError('重复调用'));
    }

    if ((typeof x === 'object' && typeof x !== null) || typeof x === 'function') {
        let then = x.then;
        if (typeof then === 'function') {
            then.call(
                x,
                y => {
                    // 递归调用,y 可能又是 promise
                    thenRetHandle(MyPromise2, y, resolve, reject);
                },
                r => {
                    reject(r);
                }
            );
        } else {
            resolve(x);
        }
    } else {
        // 不是对象或不是函数时直接返回
        resolve(x);
    }
}

// 测试结果
            const p1 = new MyPromise((resolve, reject) => {
                resolve('成功');
            });

            let p2 = p1.then(res => {
                return new MyPromise((resolve, reject) => {
                    setTimeout(() => {
                        resolve(
                            new Promise((resolve, reject) => {
                                setTimeout(() => {
                                    resolve('哈哈哈哈');
                                }, 0);
                            })
                        );
                    }, 0);
                });
            });

            let p3 = p2
                .then(res => {
                    console.log('0', res);
                    return res;
                })
                .then(res => {
                    return new Promise(resolve => {
                        setTimeout(() => {
                            console.log('1', res);
                            resolve(res);
                        }, 500);
                    });
                });

            p3.then(res => {
                console.log('p3', res);
            });
// 0 哈哈哈哈
// 1 哈哈哈哈
// p1 哈哈哈哈

4.添加错误处理及完整代码

// 等待中
const PENDING = 'pending';
// 成功
const RESOLVE = 'resolve';
// 失败
const REJECT = 'reject';

class MyPromise {
    constructor(execute) {
        try {
            execute(this.resolve, this.reject);
        } catch (e) {
            reject(e);
        }
    }

    // 当前状态
    status = PENDING;
    // 成功的数据
    value = null;
    // 失败数据
    fail = null;

    // 成功回调的集合
    onFuResolvCallback = [];
    // 失败回调的集合
    onFuRejectCallback = [];

    resolve = value => {
        if (this.status === PENDING) {
            this.value = value;
            this.status = RESOLVE;

            // 当 resolve 异步执行时 onFuResolvCallback有未执行的回调时
            while (this.onFuResolvCallback.length) {
                this.onFuResolvCallback.shift()(this.value);
            }
        }
    };

    reject = value => {
        if (this.status === PENDING) {
            this.fail = value;
            this.status = REJECT;

            // 当 reject 异步执行时 onFuResolvCallback有未执行的回调时
            while (this.onFuRejectCallback.length) {
                this.onFuRejectCallback.shift()(this.fail);
            }
        }
    };

    then(onFuResolv, onFuReject) {
        // 容错处理,使then里面的参数可以选
        onFuResolv = typeof onFuResolv === 'function' ? onFuResolv : value => value;
        onFuReject = typeof onFuReject === 'function' ? onFuReject : value => new Error(this.fail);

        // 返回一个新的 MyPromise 使其可以链式调用 then
        const MyPromise2 = new MyPromise((resolve, reject) => {
            // 成功的微任务
            const resolveMicrotask = () => {
                queueMicrotask(() => {
                    try {
                        const x = onFuResolv(this.value);
                        thenRetHandle(MyPromise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                });
            };

            // 失败的微任务
            const rejectMicrotask = () => {
                try {
                    const x = onFuReject(this.fail);
                    thenRetHandle(MyPromise2, x, resolve, reject);
                } catch (e) {
                    reject(e);
                }
            };

            if (this.status === RESOLVE) {
                resolveMicrotask();
            } else if (this.status === REJECT) {
                rejectMicrotask();
            } else if (this.status === PENDING) {
                queueMicrotask(() => {
                    this.onFuResolvCallback.push(resolveMicrotask);
                    this.onFuRejectCallback.push(rejectMicrotask);
                });
            }
        });

        return MyPromise2;
    }
}

// 每次 then 时返回值的处理
function thenRetHandle(MyPromise2, x, resolve, reject) {
    // 防止重复调用
    if (x === MyPromise2) {
        return reject(new TypeError('重复调用'));
    }

    if ((typeof x === 'object' && typeof x !== null) || typeof x === 'function') {
        let then;
        try {
            then = x.then;
        } catch (e) {
            reject(e);
        }
        if (typeof then === 'function') {
            try {
                then.call(
                    x,
                    y => {
                        // 递归调用,y 可能又是 promise
                        thenRetHandle(MyPromise2, y, resolve, reject);
                    },
                    r => {
                        reject(r);
                    }
                );
            } catch (e) {
                reject(e);
            }
        } else {
            resolve(x);
        }
    } else {
        // 不是对象或不是函数时直接返回
        resolve(x);
    }
}

5.新增静态 all 方法

class MyPromise {
    constructor(execute) {
        try {
            execute(this.resolve, this.reject);
        } catch (e) {
            reject(e);
        }
    }

    // 当前状态
    status = PENDING;
    // 成功的数据
    value = null;
    // 失败数据
    fail = null;

    // 成功回调的集合
    onFuResolvCallback = [];
    // 失败回调的集合
    onFuRejectCallback = [];

    resolve = value => {
        .........
    };

    reject = value => {
         .........
    };

    then(onFuResolv, onFuReject) {
         .........
    }

    // 新增
    static all(array) {
        // 返回的数据
        let returns = [];
        // 记数器 (用作记录是否所有任务都执行完成(异步))
        let index = 0;

        return new MyPromise((resolve, reject) => {
            // 错误处理
            if (!Array.isArray(array)) return reject(new TypeError('类型错误,请传入数组'));
            else if (array.length === 0) return resolve(array);

            // 添加返回值
            const addRet = (key, value) => {
                returns[key] = value;
                index++;
                if (index === array.length) resolve(returns);
            };

            for (let i = 0; i < array.length; i++) {
                try {
                    let current = array[i];
                    if (current instanceof MyPromise) {
                        current.then(
                            value => {
                                addRet(i, value);
                            },
                            e => {
                                reject(e);
                            }
                        );
                    } else {
                        addRet(i, current);
                    }
                } catch (e) {
                    reject(e);
                }
            }
        });
    }
}

// 测试
            let a1 = () => {
                return new MyPromise((resolve, reject) => {
                    setTimeout(() => {
                        // resolve('a3');
                        resolve(new Error('错误'));
                    }, 2000);
                });
            };

            let a2 = () => {
                return new MyPromise((resolve, reject) => {
                    resolve('a4');
                });
            };

MyPromise.all(['a1', 'a2', a1(), a2(), 'a5']).then(
                res => {
                    console.log('res', res);
                },
                e => console.log('/', e)
            );

// ["a1", "a2", Error: 错误 at eval...., "a4","a5"]

all的使用小技巧

// 注意:这里只能使用可迭代的map之类的方法,不确定是否描述的正常,但是forEach肯定会报错,map不会报错
 
Promise.all(arr.map(item => {
    // 在这里发送请求
    // 如果其中一项失败了,你并不想让其中断,可以通过 catch 捕获或者把错误的值赋值默认值之类的操作
    item.catch(e => '')
})).then(res => {
    //  res 是最后返回的结果,是一个数组
})

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值