Promise之Promise解决了什么问题

365 阅读3分钟

一、Promise解决的问题

  1. 回调地狱问题
  2. 可读性问题
  3. 信任问题(也称控制反转问题)

二、回调地狱问题

  1. 什么是回调地狱呢?笔者认为,异步的嵌套可称之为回调地狱,举个栗子🌰
    //queryData向后端请求数据
    queryData('data1', function(ret) {
        console.log(ret);  
        queryData('data2', function(ret) {
            console.log(ret);
            queryData('data3', function(ret) {
                console.log(ret);
            });
        });
    });
    
  2. 回调地狱有哪些问题呢?很典型的两个问题就是可读性问题信任问题,下面就此两点着重展开。

三、可读性问题

  1. 可读性问题可想而知,如果你看到的代码是这个样子的,是不是会疯掉
        queryData('data1', function(ret) {
            console.log(ret);  
            queryData('data2', function(ret) {
                console.log(ret);
                queryData('data3', function(ret) {
                    console.log(ret);
                    queryData('data4', function(ret) {
                        console.log(ret);  
                        queryData('data5', function(ret) {
                            console.log(ret);
                            queryData('data6', function(ret) {
                                console.log(ret);
                                //此处省略无数嵌套
                            });
                        });
                    });
                });
            });
        });
    
  2. 通过promise,可以极大程度上的提高可读性
        queryData('data1')
            .then((ret) => {
                console.log(ret);
                return queryData('data2');
            })
            .then((ret) => {
                console.log(ret);
                return queryData('data3');
            })
            .then((ret) => {
                console.log(ret);
                return queryData('data4');
            })
    

四、信任问题

  1. 为什么会产生信任问题呢? 很多时候,我们在开发中都需要依赖大量的三方库,在使用三方库的某些方法时,我们会给三方库传入回调函数,但这些三方库是否百分之百可靠? 或者说,这些三方库是否能够按照我们的设想,在正确的时间正确地调用回调? 这些问题我们不得而知。类似还会出现一些问题:
    • 回调过早/过晚/没有回调
    • 回调次数过多/过少
    • 等等
  2. 异步嵌套带来信任问题的根源在于控制反转控制反转在面向对象中的应用是依赖注入,比如AngularJS,Nest等都实现了依赖注入。但是在回调中就难以控制,我们将回调传给三方,由三方决定回调的时间以及如何调用回调。举个栗子🌰:
        ajax( "/rest/user/1", function response(res){ 
            if (res) { 
                userHandler(); 
            } else { 
                nouserHandler(); 
            } 
        }); 
        //假设ajax是一个信任度极低的三方库,repsonse的调用完全由它决定,此刻你是不是菊花一紧
    
  3. promise的出现很好地解决了这个问题,promise并没有取消控制反转,而是把反转出去的控制再次反转,将最终控制权放在自己手中。
    promise与普通回调函数的区别在于,普通回调函数将回调完完全全交给三方,控制权在第三方,而在promise中,回调只负责通知决议, 而决议后的操作则放在then中,由promise精确控制。举个栗子🌰
        Promise((rs, rj) => {
            ajax( "/rest/user/1", function response(res){ 
                if (res) { 
                    rs(res); 
                } else { 
                    rj();
                } 
            }); 
        })
        .then((res) => {
            userHandler(res); 
        },()=>{
            nouserHandler(); 
        });
        // userHandler()和nouserHandler()的调用由promise控制,回调函数仅仅进行了决议
    
    对于回调过早问题, 因为promise是异步的,所以不会出现异步的同步调用,即使在决议之前出现错误,错误也会是异步的,所以不会存在回调过早问题。
    对于回调过晚问题和没有回调的问题, 因为promise一旦决议了,就会执行相应的回调,所以不会存在回调过晚或者没有回调的问题。
    对于回调次数过多或者过少的问题, 由于promise只能被决议一次,且决议后无法改变决议结果,所以不会出现回调次数的问题。

    参考资料:
    1. Promise到底解决了什么问题