zoukankan      html  css  js  c++  java
  • 手写一个promise

    Promise A+ 规范:https://promisesaplus.com/

    注:以下代码没有通过 promises-aplus-tests 的全部测试,但基本功能还是全的( 测试结果: 864 passing, 8 failing)

    另外可以参考这个指南中的 Promise实现

    代码实现

    // Promise resolve_100+ 规范:https://promisesaplus.com/
    class myPromise {
        constructor(executor) {
            this.state = 'pending';
            this.value = undefined;
            this.reason = undefined;
            this.onResolvedArray = [];
            this.onRejectedArray = [];
            const resolve = (val) => {
                if (this.state === "pending") {
                    this.state = 'resolved';
                    this.value = val;
                    this._doResolve();
                }
            };
            const reject = (rejectReason) => {
                if (this.state === "pending") {
                    this.state = 'rejected';
                    this.reason = rejectReason;
                    this._doReject();
                }
            };
            try {
                executor(resolve, reject);
            } catch (e) {
                reject(e);
            }
        }
    
        then(onResolved, onRejected) {
            let promise2;
            promise2 = new myPromise((resolve, reject) => {
    
                // 遵循 2.2
                const afterResolved = value => {
                    try {
                        typeof onResolved === "function"
                            ? resolvePromise(promise2, onResolved(value), resolve, reject)
                            : resolvePromise(promise2, value, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                };
                const afterRejected = reason => {
                    try {
                        typeof onRejected === "function"
                            ? resolvePromise(promise2, onRejected(reason), resolve, reject)
                            : reject(reason);
                    } catch (e) {
                        reject(e);
                    }
                };
    
                // 2.1
                switch (this.state) {
                    case "pending":
                        this.onResolvedArray.push(afterResolved);
                        this.onRejectedArray.push(afterRejected);
                        break;
                    case "resolved":
                        this.onResolvedArray.push(afterResolved);
                        this._doResolve();
                        break;
                    case "rejected":
                        this.onRejectedArray.push(afterRejected);
                        this._doReject();
                        break;
                }
            });
            return promise2;
        }
    
        // 执行所有的 onResolved
        _doResolve() {
            // XXX: 模拟一下microTask
            Promise.resolve().then(() => {
                this.onResolvedArray.forEach(f => f(this.value));
                this.onResolvedArray = [];
            });
        }
    
        // 执行所有的 onRejected
        _doReject() {
            // XXX: 模拟一下microTask
            Promise.resolve().then(() => {
                // if(this.onRejectedArray.length ===0) console.error('Uncaught myPromise', this.reason && this.reason.message || this.reason);
                this.onRejectedArray.forEach(f => f(this.reason));
                this.onRejectedArray = [];
            });
        }
    
        // then(null, onRejected) 的别名
        catch(onRejected) {
            return this.then(null, onRejected);
        }
    
        static resolve(val) {
            return new myPromise((resolve) => {
                resolve(val);
            });
        }
    
        static reject(reason) {
            return new myPromise((resolve, reject) => {
                reject(reason);
            });
        }
    
        static all(promiseList) {
            return new myPromise((resolve, reject) => {
                const result = [];
                let count = 0;
                promiseList.forEach((item, index) => {
                    item
                        .then(value => {
                            count++;
                            result[index] = value;
                            if (count === promiseList.length - 1) {
                                resolve(result);
                            }
                        })
                        .catch(err => {
                            reject(err);
                        });
                });
            });
        }
    
        static race(promiseList) {
            return new myPromise((resolve, reject) => {
                promiseList.forEach(item => {
                    item.then(resolve, reject);
                });
            });
        }
    
        // 下面两个是为了测试才加的
    
        static deferred() {
            let dfd = {};
            dfd.promise = new myPromise(function (resolve, reject) {
                dfd.resolve = resolve;
                dfd.reject = reject;
            });
            return dfd;
        }
    
        static defer() {
            let dfd = {};
            dfd.promise = new myPromise(function (resolve, reject) {
                dfd.resolve = resolve;
                dfd.reject = reject;
            });
            return dfd;
        }
    }
    
    // 处理onResolve返回promise时的情况
    function resolvePromise(promise, x, resolve, reject) {
        let called = false;
        if (promise === x) {
            if (called) return;
            called = true;
            reject(new TypeError('promise 循环错误'));
            console.error('promise 循环错误');
            return;
        }
        try {
            if (Object.prototype.toString.call(x) === "[object Object]" || typeof x === "function") {
                const then = x.then;
                if (typeof then === "function") {
                    then.call(
                        x,
                        value => {
                            if (called) return;
                            called = true;
                            resolvePromise(promise, value, resolve, reject);
                        },
                        reason => {
                            if (called) return;
                            called = true;
                            reject(reason);
                        }
                    );
                } else {
                    if (called) return;
                    called = true;
                    resolve(x);
                }
            } else {
                if (called) return;
                called = true;
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    }
    
    try {
        module.exports = myPromise;
    } catch (e) {
    
    }
    
    

    简单测试

        function test(promiseConstructor) {
            function log(msg) {
                console.log(promiseConstructor.name + '		', msg);
            }
    
            const testCase = [
                {
                    ["测试同步promise"]() {
                        let resolve_immediate = promiseConstructor.resolve('immediate');
                        resolve_immediate.then(value => {
                            log('resolved', value);
                        });
                        let reject_immediate = promiseConstructor.reject('immediate');
                        reject_immediate.catch(value => {
                            log('rejected', value);
                        });
                    }
                },
                {
                    ["测试异步promise"]() {
                        new promiseConstructor((resolve) => {
                            setTimeout(() => {
                                resolve(1);
                            }, 100);
                        })
                            .then(val => log('resolve', val));
                        new promiseConstructor((resolve, reject) => {
                            setTimeout(() => {
                                reject(2);
                            }, 100);
                        })
                            .catch(val => log('reject1', val));
                    }
                },
                {
                    ["测试链式调用和throw方法"]() {
                        new promiseConstructor((resolve) => {
                            setTimeout(() => {
                                resolve(1);
                            }, 100);
                        })
                            .then(value => {
                                log(value);
                                return value + 1;
                            })
                            .catch(value => {
                                log('我不应该出现', value);
                                return value + 1;
                            })
                            .then(value => {
                                log(value);
                                throw value + 1;
                            })
                            .catch(value => {
                                log(value);
                                throw value + 1;
                                // return value + 1;
                            })
                            .then(value => {
                                log(value);
                            })
                            .catch(log);
                    }
                },
                {
                    ["测试返回promise"]() {
                        new promiseConstructor((resolve) => {
                            setTimeout(() => {
                                resolve(1);
                            }, 100);
                        })
                            .then(value => {
                                return new promiseConstructor((resolve) => {
                                    setTimeout(() => {
                                        resolve(value + 1);
                                        resolve(value + 1); // 这里重复调用了resolve,但是并不会有什么后果
                                    });
                                });
                            })
                            .then(value => {
                                log(value);
                                return value + 1;
                            })
                            .then(value => {
                                return new promiseConstructor((resolve, reject) => {
                                    setTimeout(() => {
                                        reject(value + 1);
                                        resolve(value + 1); // 这里重复调用了resolve,但是并不会有什么后果
                                    });
                                });
                            })
                            .catch(value => {
                                log(value);
                                return value + 1;
                            });
                    }
                },
                {
                    ["测试promise.all"]() {
                        promiseConstructor.all([
                            promiseConstructor.resolve(1),
                            promiseConstructor.resolve(2)
                        ])
                            .then(log)
                            .catch((err) => {
                                log(err, '我不出现');
                            });
                        promiseConstructor.all([
                            promiseConstructor.reject(1),
                            promiseConstructor.resolve('我不出现1'),
                            promiseConstructor.reject('我不出现2'),
                        ])
                            .then((err) => {
                                log(err, '我不出现');
                            })
                            .catch(log);
                    }
                },
                {
                    ["测试promise.race"]() {
                        promiseConstructor.race([
                            new promiseConstructor(resolve => {
                                setTimeout(() => {
                                    resolve('我不出现');
                                }, 200);
                            }),
                            new promiseConstructor(resolve => {
                                setTimeout(() => {
                                    resolve(1);
                                }, 100);
                            })
                        ])
                            .then(log)
                            .catch((err) => {
                                log(err, '我不出现');
                            });
                        promiseConstructor.race([
                            promiseConstructor.reject(1),
                            promiseConstructor.resolve('我不出现1'),
                            promiseConstructor.reject('我不出现2'),
                        ])
                            .then((err) => {
                                log(err, '我不出现');
                            })
                            .catch(log);
                    }
                },
                {
                    ["测试循环promise"]() {
                        let a = new promiseConstructor(resolve => {
                            setTimeout(() => {
                                resolve(1);
                            }, 100);
                        })
                            .then(value => {
                                return 2;
                            })
                            .then(value => {
                                log(value, '应该报循环引用错误2');
                                return a;
                            });
                        // 不知道为什么,这里如果加一个.catch或者.then就不会报错了
                        // 原生的promise也是这样
                    }
                }
            ];
            for (let i = 0, len = testCase.length; i < len; i++) {
                const item = testCase[i];
                setTimeout(() => {
                    const name = Object.keys(item)[0];
                    console.group(name);
                    item[name]();
                    setTimeout(() => {
                        console.groupEnd();
                    }, 900);
                }, i * 1000);
            }
        }
        test(myPromise);
        test(Promise);
    
  • 相关阅读:
    回归测试
    系统测试
    单元测试
    软件测试规律之木桶原理
    集成测试
    软件测试度量
    测试用例设计方法之错误推测法
    测试用例设计方法之因果图方法
    有趣的算法:1元=1分
    【转】 arcServer 一些 FAQ
  • 原文地址:https://www.cnblogs.com/wozho/p/10565931.html
Copyright © 2011-2022 走看看