interview-answe icon indicating copy to clipboard operation
interview-answe copied to clipboard

212.必须要会的手写Promise

Open webVueBlog opened this issue 5 years ago • 3 comments

[js]

webVueBlog avatar Apr 27 '20 07:04 webVueBlog

Promise是一个管理异步编程的方案,它是一个构造函数,每次使用可用new创建实例;它有三种状态:pending、fulfilled和rejected,这三种状态不会受外界影响,状态只能由pending变为fullfilled(成功),pending变为rejected(失败),且一旦改变就不会再改变,在状态改变后,它会返回成功的结果或者失败的原因,它对外抛出了resolve、reject、catch、finally、then、all、race、done,在最新的提案中,添加了allSettled方法,它不管成功、失败都会返回,接下来,我们自己实现整个Promise

webVueBlog avatar Apr 27 '20 07:04 webVueBlog

class MyPromise{
    constructor(executor) {
        this.status = "pending";     // 初始化状态为pending
        this.value = undefined;      // 初始化返回的成功的结果或者失败的原因
        
        // 这里是resolve方法,成功后执行,将状态改变为resolved,并且将结果返回
        let resolve = result => {
            if(this.status !== "pending") return;  // 状态一旦改变,就不会再变
            this.status = "resolved";
            this.value = result;
        }
        
        // 这里是reject方法,异常时执行,状态改为rejected,并且将失败的原因返回
        let reject = reason => {
            if(this.status !== "pending") return;
            this.status = "rejected";
            this.value = reason;
        }
        // try、catch捕获异常,如果错误,执行reject方法
        try {
            executor(resolve, reject)
        } catch(err) {
            reject(err)
        }
    }
}

webVueBlog avatar Apr 27 '20 07:04 webVueBlog

then(resolveFn, rejectFn) {
    // 如果传入的两个参数不是函数,则直接执行返回结果
    let resolveArr = [];
    let rejectArr = [];
    
    if(typeof resolveFn !== "function") {
        resolveFn = result => {
            return result;
        }
    }
    
    if(typeof rejectFn !== "function") {
        rejectFn = reason => {
            return MyPromise.reject(reason);
        }
    }
    
    return new Mypromise((resolve, reject) => {
        resolveArr.push(result => {
            try {
                let x = resolveFn(result);
                
                if(x instanceof MyPromise) {
                    x.then(resolve, reject)
                    return;
                }
                
                resolve(x);
            } catch(err) {
                reject(err)
            }
        })
        
        rejectArr.push(reason => {
            try {
                let x = rejectFn(reason);
                
                if(x instanceof MyPromise) {
                    x.then(resolve, reject)
                    return;
                }
                
                resolve(x);
            } catch(err) {
                reject(err)
            }
        })
    })
}

webVueBlog avatar Apr 27 '20 07:04 webVueBlog