Promise简易版实现


/**
 * Readme:
 * EasyPromise
 * 本文实现了简易版的Promise类,实现功能包括:
 * EasyPromise.prototype.then()
 * EasyPromise.prototype.catch()
 * EasyPromise.prototype.finally()
 * EasyPromise.all()
 * EasyPromise.race()
 * TODO: 其他Promise内置api
 * 代码的最下方提供了测试EasyPromise的api的demo,可以直接复制代码到本地.js,通过html引入即可直接运行
 * 本实现 基于本人比较粗浅的理解,只实现了基本脉络,具体细节可能不是很严谨,仅供参考
 */
class EasyPromise {
    static resolveCbStatic = undefined; // 供EasyPromise.all等静态方法使用
    static rejectCbStatic = undefined; // 供EasyPromise.all等静态方法使用

    resolveCb = undefined; // status == resolved 的回调
    rejectCb = undefined; // status == reject 的回调
    finallyCb = undefined; // status == resolved || status == reject 的回调,此方法无入参,
                           // 不依赖于 Promise 的执行结果
    resolveData = undefined; // status == resolved 数据存储
    rejectData = undefined; // status == reject 数据存储
    status = 'pending'; // 记录Promise传入的异步任务状态

    constructor (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('EasyPromise方法传参无效')
            return false;
        }
        this._resolve = this._resolve.bind(this)
        this._reject = this._reject.bind(this)
        this.then = this.then.bind(this)
        this.catch = this.catch.bind(this)
        this.finally = this.finally.bind(this)

        fn(this._resolve, this._reject)
    }
    _resolve (data) {
        if (this.status == 'pending') {
            this.status = 'resolved';
            this.resolveData = data;
            this.resolveCb && this.resolveCb(data)
            this.finallyCb && this.finallyCb()
        }
    }
    _reject (err) {
        if (this.status == 'pending') {
            this.status = 'rejected';
            this.rejectData = err;
            this.rejectCb && this.rejectCb(data)
            this.finallyCb && this.finallyCb()
        }
    }
    then (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('then方法传参无效')
            return false;
        }
        // 链式编程(关键代码)
        return new EasyPromise((resolve, reject) => {
            this.resolveCb = () => {
                let ret = fn(this.resolveData);
                if (ret && ret.constructor == EasyPromise) {
                    ret.then((data) => {
                        resolve(data)
                    })
                } else {
                    resolve(ret)
                }
            };
            if (this.status == 'resolved') {
                this.resolveCb(this.resolveData)
            }
        })
    }
    catch (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('catch方法传参无效')
            return false;
        }
        this.rejectCb = fn;
        if (this.status == 'rejected') {
            this.resolveCb(this.rejectData)
        }
        return this; // 链式编程
    }
    finally (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('finally方法传参无效')
            return false;
        }
        this.finallyCb = fn;
        if (this.status == 'resolved' || this.status == 'rejected') {
            this.finallyCb()
        }
    }
    // 传入多个promise实例,当所有实例都执行结束后,返回结果的数组。如果任一实例catch,则all方法停止
    static all (promiseList) {
        if (!promiseList || Object.prototype.toString.call([]) != '[object Array]') { 
            console.log('all方法传参无效')
            return false;
        }
        let len = promiseList.length;
        let count = 0;
        let res = [];
        let catchFlag = false;
        let invalid = false;
        promiseList.forEach((item) => {
            if (!item || item.constructor != EasyPromise) {
                invalid = true;
            } 
        })
        if (invalid) {
            console.log('promiseList 内包含不是EasyPromise的实例')
            return false;
        }
        promiseList.forEach((item, index) => {
            if (catchFlag) {
                return false;
            }
            item.then((data) => {
                count += 1;
                res[index] = data;
                if (len == count) { // 所有任务处理成功
                    this.resolveCbStatic(res)
                }
            }).catch(() => { // 任一任务出现错误
                catchFlag = true;
                this.rejectCbStatic(`all 方法调用错误, 对应索引-${index}`)
            })
        })
        return this;
    }
    // 供all,race等静态方法使用
    static then (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('then方法传参无效')
            return false;
        }
        this.resolveCbStatic = fn;
        return this;
    }
    // 供all,race等静态方法使用
    static catch (fn) {
        if (!fn || typeof fn != 'function') { 
            console.log('catch方法传参无效')
            return false;
        }
        this.rejectCbStatic = fn;
    }
    // 传入多个promise实例,返回最快执行结束的那个
    static race (promiseList) {
        if (!promiseList || Object.prototype.toString.call([]) != '[object Array]') { 
            console.log('all方法传参无效')
            return false;
        }
        let invalid = false;
        let status;
        promiseList.forEach((item) => {
            if (!item || item.constructor != EasyPromise) {
                invalid = true;
            } 
        })
        if (invalid) {
            console.log('promiseList 内包含不是EasyPromise的实例')
            return false;
        }
        promiseList.forEach((item, index) => {
            item.then((data) => {
                if (status == 'end') {
                    return false;
                }
                status = 'end';
                this.resolveCbStatic(data)
            }).catch((err) => {
                this.rejectCbStatic(`race 方法调用错误`)
            })
        })
        return this;
    }
}

/**
 * 测试EasyPromise基础功能 打开注释即可
 */
// new EasyPromise((resolve, reject) => {
//     let data = { value: '我是异步响应的数据' }
//     setTimeout(function () {
//         let flag = true;
//         if (flag) {
//             resolve(data)
//         } else {
//             reject('异步处理异常')
//         }
//     }, 1000)
// })
// .then((data)  => {
//     console.log(`响应数据为:`, data)
//     return '哈哈哈'
// })
// .then((data) => {
//     console.log(data, '第二个then的数据')
//     return new EasyPromise((resolve, reject) => {
//         setTimeout(function () {
//             resolve('呵呵呵')
//         }, 1000)
//     })
// })
// .then((data) => {
//     console.log(data, '第三个then的数据')
// })
// .catch((err)  => {
//     console.log(`发生错误:${err}`)
// })
// .finally((data)  => {
//     console.log(`我是finally触发`)
// })

/**
 * 测试 EasyPromise.all 方法 打开注释即可
 */
// let promise1 = new EasyPromise((resolve, reject) => {
//     setTimeout(function () {
//         resolve('呵呵呵')
//     }, 2000)
// })

// let promise2 = new EasyPromise((resolve, reject) => {
//     setTimeout(function () {
//         resolve('哈哈哈')
//     }, 1000)
// })
// EasyPromise.all([ promise1, promise2 ])
// .then((data) => {
//     console.log(data)
// })
// .catch((err) => {
//     console.log(err)
// })

/**
 * 测试 EasyPromise.race 方法 打开注释即可
 */
// let promise3 = new EasyPromise((resolve, reject) => {
//     setTimeout(function () {
//         resolve('呵呵呵')
//     }, 2000)
// })

// let promise4 = new EasyPromise((resolve, reject) => {
//     setTimeout(function () {
//         resolve('哈哈哈')
//     }, 1000)
// })
// EasyPromise.race([ promise3, promise4 ])
// .then((data) => {
//     console.log(data)
// })
// .catch((err) => {
//     console.log(err)
// })
 

 

posted @ 2020-12-28 15:20  秋叶枫麓  阅读(87)  评论(0)    收藏  举报