美文网首页
前端面试经典Promise理解与总结

前端面试经典Promise理解与总结

作者: WEB前端含光 | 来源:发表于2020-07-15 21:51 被阅读0次

    Promise作为面试中的经典考题,我们一定要深刻学习和理解它! Promise有什么用呢?答:我们拿它解决异步回调问题。

    概念

    异步回调的一个很大的问题在于callback hell也就是“回调地狱”。多层嵌套回调函数,严重影响代码规范。Promise实际上是把回调函数从doSomething函数中提取到了后面的then()方法里,从而防止多重嵌套。一个Promise对象表示目前还不可用但是未来某个节点可以被解析的值,这个值要么被解析成功,要么失败抛出异常。它允许我们以同步的方式编写异步代码。

    使用方法

    Promise的构造函数用来构造一个Promise对象,其中入参匿名函数中resolve和reject这两个也都是函数。如果resolve执行了,则出发Promise.then中成功的回调函数,如果reject执行了,则触发了promise.then中拒绝的回调函数。

    一个Promise对象一开始的值是pending准备状态,执行了resolve()后,Promise对象的状态值变为onFulfilled,执行了reject()后,状态值变为onRejected。Promise对象的状态值一旦确定,就不会再改变。

    异常捕获

    promise有两种异常捕获方式,一个是then中的reject,另一个是catch()方法。

    then中的reject方法捕获异常

    无法捕获当前then中抛出的异常

    var promise = Promise.resolve();
    promise.then(()=>{
        throw new Error("BOOM!");
    }).then((success)=>{
        console.log(success);
    }, (error)=>{
        console.log(error);
    });
    复制代码
    

    catch捕获异常

    catch不仅能捕获then中抛出的异常,还能捕获前面promise抛出的异常,所以建议使用catch方法。

    var promise = Promise.reject("Boom!");
    promise.then(()=>{
        return "success";
    }).then((success) => {
        console.log(success);
        throw new Error("Another Boom!");
    }).catch((error) => {
        console.log(error); //BOOM!
    });
    复制代码
    

    手写Promise
    基础篇-小试牛刀

    首先来看基础版的代码,可以实现简单的同步代码,这一步是必须要能够写出来的。

    // 首先要明确Promise是一个类,所以我们用class声明。
    // 其次,构造函数中接收一个executor,它有两个参数,一个是resolve,一个是reject
    // 这里要注意,resolve和reject都是函数
    class Promise(){
        // 构造函数(入参是执行器,包括resolve和reject两个函数)
        constructor(executor){
            // 必要的初始化,这里用到状态,值和原因三个变量
            this.state = 'pending';
            this.value = undefined;
            this.reason = undefined;
            // 定义成功函数,入参是value
            let resolve = value => {
                // 首先要判断state是否为等待态,如果不是则不做任何处理
                if(this.state === 'pending'){
                    // 修改状态
                    this.state = 'fulfilled';
                    // 更新值
                    this.value = value;
                }
            };
            // 定义失败函数,入参是失败原因
            let reject = reason => {
                // 同样的逻辑
                if(this.state === 'pending'){
                    this.state = 'rejected';
                    this.reason = reason;
                }
            };
            // 这是promise对象的的主逻辑,执行executor,如果执行器出错,则捕获错误后执行reject函数
            try{
                executor(resolve, reject); 
            }catch(err){
                reject(err);
            }
        }
        // 定义Promise的then函数
        // then方法接收两个参数,如果状态为fulfilled,执行onFulfilled
        // 如果状态为rejected,则执行onRejected
        then(onFulfilled, onRejected){
            if(this.state === 'fulfilled'){
                onFulfilled(this.value);
            };
            if(this.state === 'rejected'){
                onRejected(this.reason);
            };
        }
    }
    复制代码
    

    进阶篇 解决异步实现

    class Promise{
        constructor(executor){
            this.state = 'pending';
            this.value = undefined;
            this.reason = undefined;
            // 成功回调函数数组和失败回调函数数组
            this.onResolveCallbacks = [];
            this.onRejectedCallbacks = [];
            let resolve = value => {
                if(this.state === 'pending'){
                    this.state = 'fulfilled';
                    this.value = value;
                    // 成功的话遍历成功回调函数数组然后执行这些函数
                    this.onResolvedCallbacks.forEach(fn=>fn());
                }
            };
            let reject = reason => {
                if(this.state === 'pending'){
                    this.state = 'rejected';
                    this.reason = reason;
                    // 失败的话遍历失败回调函数数组然后执行这些函数
                    this.onRejectedCallbacks.forEach(fn=>fn());
                }
            };
            try{
                executor(resolve,reject)
            }catch(err){
                reject(err);
            }
            then(onFulfilled, onRejected){
                if(this.state === 'fulfilled'){
                    onFulfilled(this.value);
                }
                if(this.state === 'rejected'){
                    onRejected(this.reason);
                }
                // 当状态为等待态时,我们要将成功/失败的回调函数加入到对应的数组中
                if(this.state === 'pending'){
                    // onFulfilled传入到成功数组
                    this.onResolvedCallbacks.push(()=>{
                        onFulfilled(this.value);
                    })
                    // onRejected传入到成功数组
                    this.onRejectedCallbacks.push(()=>{
                        onRejeced(this.reason);
                    })
                }
            }
        }
    }
    复制代码
    

    威力加强版 解决链式调用

    class Promise{
        constructor(executor){
            this.state = 'pending';
            this.value = undefined;
            this.reason = undefined;
            this.onResolvedCallbacks = [];
            this.onRejectedCallbacks = [];
            let resolve = value => {
                if(this.state === 'pending'){
                    this.state = 'fulfilled';
                    this.value = value;
                    this.onResolvedCallbacks.forEach(fn=>fn());
                }
            };
            let reject = reason => {
                if(this.state === 'pending'){
                    this.state = 'rejected';
                    this.reason = reason;
                    this.onRejectedCallbacks.forEach(fn=>fn());
                }
            };
            try{
                executor(resolve,reject);
            }catch(err){
                reject(err);
            }
        }
        then(onFulfilled, onRejected){
            let promise2 = new Promise((resolve,reject) => {
                if(this.state === 'fulfilled'){
                   let x = onFulfilled(this.value); 
                   resolvePromise(promise2, x, resolve, reject);
                };
                if(this.state === 'rejected'){
                    let x = onRejected(this.reason);
                    resolvePromise(promise2, x, resolve, reject);
                };
                if(this.state === 'pending'){
                    this.onResolvedCallbacks.push(()=> {
                        let x = onFulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    })
                    this.onRejectedCallbacks.push(()=>{
                        let x = onRejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    })
                };
            });
            return promise2;
        }
        function resolvePromise(promise2, x, resolve, reject){
            if(x === promise2){
                return reject(new TypeError('Chaining cycle detected for promise');
            }
            let called;
            if(x != null && (typeof x === 'object' || typeof x === 'function')){
                try{
                    let then = x.then;
                    if(typeof then === 'function'){
                        then.call(x, y=>{
                            if(called){
                                return;
                            }
                            called = true;
                            resolvePromise(promise2,y,resolve,reject);
                        }, err => {
                            if(called) return;
                            called = true;
                            reject(err);
                        })
                    }else{
                        resolve(x);
                    }
                }catch(e){
                    if(called) return;
                    called = true;
                    reject(e);
                }
            }else{
                resolve(x);
            }
        }
    }
    复制代码
    

    有想了解更多的小伙伴可以加Q群链接里面看一下,应该对你们能够有所帮助。里面有许多学习资料和面试文档 以及免费的进阶技术分享。

    相关文章

      网友评论

          本文标题:前端面试经典Promise理解与总结

          本文链接:https://www.haomeiwen.com/subject/jzcfhktx.html