Promise规范

Promise的出现就是为了解决冗长的callback造成的不便如:

 loadImg('a.jpg', function() {
     loadImg('b.jpg', function() {
         loadImg('c.jpg', function() {
             console.log('all done!');
         });
     });
 });

这样的代码不方便调试和观看 而且多了之后会越来越向右边推挤


Promise,就是一个对象,用来传递异步操作的消息。它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个事件提供统一的 API,可供进一步处理。
字面上可以理解为“承诺”,就是说A调用B,B返回一个“承诺”给A,然后A就可以在写计划的时候这么写:当B返回结果给我的时候,A执行方案S1,反之如果B因为什么原因没有给到A想要的结果,那么A执行应急方案S2,这样一来,所有的潜在风险都在A的可控范围之内了。

  • 一个promise可能有三种状态:等待(pending)、已完成(fulfilled)、已拒绝(rejected)
  • 一个promise的状态只可能从“等待”转到“完成”态或者“拒绝”态,不能逆向转换,同时“完成”态和“拒绝”态不能相互转换
  • promise必须实现then方法(可以说,then就是promise的核心),而且then必须返回一个promise,同一个promise的then可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致
  • then方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then可以接受另一个promise传入,也接受一个“类then”的对象或方法,即thenable对象。

promise也是CommonJS规范的一部分

最简单的Promise例子

function run(arg1, callback){
            //....
            callback || callback();
        }

        run(arg1, function(){
            run(arg2, function(){
                run(arg3, function(){
                    //.....一直嵌套下去
                });
            });
        });

这是传统的方法

使用Promise
function run(arg){
            return new Promise(function(resolve, reject){
                //..... do something
                if(success){
                    resolve(arg);
                }else {
                    reject();
                }
            });
        }

        run(arg1)
            .then(function(arg1){
                //success
                //do something
            },function(arg1){
                //wrong
                //do something
            })
            .then(function(arg2){
                //success
                //do something
            },function(arg2){
                //wrong
                //do something
            })
            .then(function(arg3){
                //success
                //do something
            },function(arg3){
                //wrong
                //do something
            });

简单来说,Promise规范就是定义一个function,这次不需要定义他的callback了,只需要return一个Promise对象,这个对象的构造函数接受一个匿名函数,匿名函数里定义这个function正常的功能,如果function执行成功了,调用resolve方法,这个方法可以接受一个参数,那么下个执行的函数将会接收到这个参数。反之,失败了定义执行reject。

调用时,执行该函数,在执行下一个函数时使用.then方法,正确执行对于的代码和错误执行对应的代码对应写入到then中,这样可以链式执行函数。
注意Promise执行之后,必须返回一个Promise对象才可执行下一个then方法,所以then方法中的函数一定返回Promise对象才可。

兼容性方面 高版本的主流浏览器都有内置的Promise对象,因为这个ES6的规范,较低版本的浏览器可以通过引入第三方的库来实现,例如bulebird。在nodejs中也无需npm模块,只需require(“Promise”);即可

下一个例子,一个动画效果 ,分别使用常规的方法实现,和Promise方法实现,对比下不同。
<!doctype html>
<!DOCTYPE html>
<html>
<head>
    <title>Promise animate</title>
    <style>
        .ball {
            width:40px;
            height:40px;
            border-radius:20px;
        }
        .ball1 {
            background: red;
        }
        .ball2 {
            background: blue;
        }
        .ball3 {
            background: yellow;
        }
        .ball4 {
            background: black;
        }
        .ball5 {
            background: pink;
        }
        .ball6 {
            background: green;
        }
    </style>
    <script type="text/javascript" src="./node_modules/bluebird/js/browser/bluebird.js"></script>
</head>
<body>
    <div class="ball ball1" style="margin-left:0;"></div>
    <div class="ball ball2" style="margin-left:0;"></div>
    <div class="ball ball3" style="margin-left:0;"></div>

    <div class="ball ball4" style="margin-left:0;"></div>
    <div class="ball ball5" style="margin-left:0;"></div>
    <div class="ball ball6" style="margin-left:0;"></div>

    <script>
        var ball1 = document.querySelector('.ball1');
        var ball2 = document.querySelector('.ball2');
        var ball3 = document.querySelector('.ball3');

        var ball4 = document.querySelector('.ball4');
        var ball5 = document.querySelector('.ball5');
        var ball6 = document.querySelector('.ball6');
        var Promise = window.Promise;

        promiseAnimate(ball1, 100)
            .then(function() {
                return promiseAnimate(ball2, 200);
            })
            .then(function() {
                return promiseAnimate(ball3, 300);
            })
            .then(function() {
                return promiseAnimate(ball3, 150);
            })
            .then(function() {
                return promiseAnimate(ball2, 150);
            })
            .then(function() {
                return promiseAnimate(ball1, 150);
            });

        function promiseAnimate(ball, distance){
            return new Promise(function(resolve, reject){
                _animate();

                function _animate(){
                    setTimeout(function(){
                        var marginLeft = parseInt(ball.style.marginLeft, 10);
                        if(marginLeft === distance){
                            resolve();
                        }else {
                            if(marginLeft < distance){
                                marginLeft++;
                            }else {
                                marginLeft--;
                            }

                            ball.style.marginLeft = marginLeft + "px";

                            _animate();
                        }
                    }, 13);
                }
            });
        }    

        animate(ball4, 100, function(){
            animate(ball5, 200, function(){
                animate(ball6, 300, function(){
                    animate(ball6, 150, function(){
                        animate(ball5, 150, function(){
                            animate(ball4, 150, function(){
                                //alert("done");
                            });
                        });
                    });
                });
            });
        });

        function animate(ball, distance, cb){
            setTimeout(function(){
                var marginLeft = parseInt(ball.style.marginLeft, 10);

                if(marginLeft === distance){
                    cb && cb();
                }else {
                    if(marginLeft < distance){
                        marginLeft++;
                    }else {
                        marginLeft--;
                    }

                    ball.style.marginLeft = marginLeft + "px";

                    animate(ball, distance, cb);
                }
            }, 13);
        }
    </script>
</body>
</html>

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页