浅谈Promise

浅谈Promise

Promise主要用于更好地实现javascript中的异步编程
首先说一下基本的异步编程中存在的问题。

setTimeout

把回调函数放在事件循环中,如果此时事件循环队列中已有任务,回调需要等待,通常没有抢占,因此setTimeout精准度不高,一般会在设定的时间之后才触发回调。

回调的问题

  • 控制反转,导致信任链断裂。
  • 顺序性无法保证(Zalgo)

Promise

  • 好处

    1. 解决回调地狱----链式调用
    2. 控制反转问题----回调只调用一次
  • 规范

    1. 三种状态:Pending、fulfilled、rejected
    2. 一旦决议,状态保持不变
    3. 必须实现then方法(resolve, reject),否则Promise就失去了意义。注意:如果then里面没有实现reject则会进入catch
    4. 接受和拒绝的回调,都只接受一天参数,后面的参数会被自动忽略,如需传递多个参数,可以封装为数组或对象
  • 使用
    revealing constructor: 直接通过传入函数实例化Promise对象new Promise(function(resolve, reject){})

    var p1 = new Promise(function(resolve, reject){
        var timeOut = Math.random() * 2;
        console.log("Promise test1!");
        setTimeout(function(){
            if (timeOut > 1) {
                console.log("call resolve");
                resolve('200 OK');
            }else {
                console.log("call reject");
                reject('timeout in ' + timeOut + ' seconds');
            }
        }, 1000 * timeOut);
    }).then(
    	function(result){
            console.log(result);
        }, function(err){
            console.log(err);
        }
    )
    
    /*运行结果1:
    Promise test1!
    call resolve
    200 OK
    
    运行结果2:
    Promise test1!
    call reject
    timeout in 0.9950313377246083 seconds
    */
    

    promise函数:以Promise作为返回值的函数

    // define function
    function promise_test(){
        return new Promise(function(resolve, reject){
            var timeOut = Math.random() * 2;
            console.log("Promise test form test function!");
            setTimeout(function(){
                if (timeOut > 1) {
                    console.log("call resolve");
                    resolve('200 OK');
                }else {
                    console.log("call reject");
                    reject('timeout in ' + timeOut + ' seconds');
                }
            }, 1000 * timeOut);
        });
    }
    // call function
    promise_test()
    .then(
    	function(result){
            console.log(result);
        }, function(err){
            console.log(err);
        }
    )
    /*
    结果1:
    Promise test form test function!
    call resolve
    200 OK
    
    结果2:
    Promise test form test function!
    call reject
    timeout in 0.6580752245539725 seconds
    */
    
  • 链式调用then返回的仍然是一个promise对象,所以可以继续调用then

    promise_test()
    .then(
        function(result){
            console.log("then_0:"+result);
            return "data from then_0";
        }, function(err){
            return "err from then_0";
        }
    ).then(
        function(result){
            console.log("then_1:"+result);
            return "data from then_1";
        }, function(err){
            return "err from then_1";
        }
    ).then(
        function(result){
            console.log("then_2:"+result);
            return "data from then_2"
        }, function(err){
            return "err from then_2";
        }
    ).then(
        function(result){
            console.log("then_3:"+result);
        }, function(err){
            return "err from then_3";
        }
    ).catch(function(reason){
        console.log(reason);
    });
    
    /*
    结果1:
    call resolve
    then_0:200 OK
    then_1:data from then_0
    then_2:data from then_1
    then_3:data from then_2
    
    结果2:
    call reject
    then_1:err from then_0
    then_2:data from then_1
    then_3:data from then_2
    */
    

    当然,你也可以不用在所有的then中实现reject,只需要在最后增加一个catch捕获异常即可。比如:

    promise_test().then(function(result){
        console.log(result);
    }).then(function(result){
        console.log("then_1:"+result);
        return "data from then_1"
    }).then(function(result){
        console.log("then_2:"+result);
        return "data from then_2"
    }).then(function(result){
        console.log("then_3:"+result);
    }).catch(function(reason){
        console.log(reason);
    });
    
    /*
    结果1:
    Promise test form test function!
    call resolve
    200 OK
    then_2:data from then_1
    then_3:data from then_2
    
    结果2:
    Promise test form test function!
    call reject
    timeout in 0.9641669406602742 seconds
    

    说明:在这里的链式Promise中,状态被拒绝,由于每个then中都没有定义reject,因此直接进入到最后的catch块中(如果在中间某个then中定义reject,仍然能进入reject的逻辑)

  • 并行Promise.all(与门)promise数组中所有的promise都被接受才被接受,只要有任何一个promise被拒绝就被拒绝。

    /*例子中每一个promise都会正常返回,所以也没有使用catch*/
    function getRandomNum(num){
        return new Promise(function(resolve, reject){
            var timeOut = Math.random() * 2;
            setTimeout(function(){
                resolve(num * timeOut);
            }, 1000 * timeOut);
        });
    }
    
    Promise.all([getRandomNum(1), getRandomNum(2), getRandomNum(3)])
    .then(function([num1, num2, num3]){
        // 函数接收一个数组参数,表示几个promise返回的数据
        console.log("num1:" , num1);
        console.log("num2:" , num2);
        console.log("num3:" , num3);
        console.log("num1 + num2 + num3 :", num1 + num2 + num3);
    });
    
    /*
    num1: 0.4254007834181297
    num2: 0.10943891453033672
    num3: 0.34640854515410746
    num1 + num2 + num3 : 0.8812482431025739
    */
    
  • 静态Promise.race(或门)promise数组里第一个被接受或者被拒绝的promise决定最终的promise状态

    function getRandomNum(num){
        return new Promise(function(resolve, reject){
            var timeOut = Math.random() * 2;
            setTimeout(function(){
            	// 参数类型校验
                if ("number" === typeof num) {
                    console.log("random num " + num + ":" + num * timeOut);
                    resolve(num * timeOut);
                }else {
                    reject("TypeError!");
                }
            }, 1000 * timeOut);
        });
    }
    
    // 传入"1"会被拒绝
    Promise.race([getRandomNum("1"), getRandomNum(2)])
    .then(function(result){
        console.log("result:" , result);
    }).catch(function(reason){
        console.log(reason);
    });
    
    /*
    结果1:第一个promise先被拒绝
    TypeError!
    random num 2:1.21016497709787
    
    结果2: 第二个promise先被接受,第一个promise虽然被拒绝,但是无法进入catch
    random num 2:3.723485222889881
    result: 3.723485222889881
    */
    

    这里再强调一下Promise一旦决议,状态不可变。所以上述竞态例子中,第一个决议的Promise决定了数据的决议结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值