• 【前端】主流API-promise解析,js基础。


    前言

      在js领域,promise出现的时间已经很久了,从jquery的$.get().done().fail() 这样的API开始,到现在的es6默认支持的new Promise(),它的出现无疑使异步代码变得信任可靠,更使得前端代码的信任度直线提升,就跟它的名字一样,它的到来,是一个 Promise (保证,允诺)

    异步信任问题

      有一个朋友在银行系统工作,有一次,我帮他review一段代码,据他所说,这段代码给他带来了一个很大的麻烦,有一位顾客使用这个页面付款的时候意外的提交了两次付款请求,boss复查发现提交的源头是前端,当我接到这段代码的时候,这位朋友已经焦头烂额,我接过了代码, 初步分析,什么也没发现,他的代码就像下面这样:

    $("btn").on("click",function(){
                        if($(this).hasClass("no-submit")){
                            $(this).removeClass("no-submit");
                            //忽略
                            $.ajax({
                                url:"....",
                                type:"json",
                                success:function(){
                                    submit();
                                }
                            })
                        }
                    })

    他告诉我,他已经针对按钮做点击唯一提交了,怎么可能调用两次?

    但是事实就是有两次submit。

    通过分析代码,最后排查的结果,原因是这个jquery的$.ajax是被二次封装过的,某种情况下回调函数被调用了两次。

    oh,看起来很简单的原因,这可是个巨坑! 日常代码中,我们都需要接触各种各样的第三方库,谁来保证它们都没有隐藏的问题?如果你遇到了经过加密混淆的库,因为它内部某个try catch,或者内部某个if在非正常情况下发成的误判导致重复调用,我想你就不会再淡定的喝着咖啡敲代码了。

    或者你觉得,防止重复调用这个很简单,加个判断就行了:

    var a = 0;
                    $("btn").on("click",function(){
                        if($(this).hasClass("no-submit")){
                            $(this).removeClass("no-submit");
                            //忽略
                            $.ajax({
                                url:"....",
                                type:"json",
                                success:function(){
                                    if( a==0){
                                        submit();
                                    }
                                    
                                }
                            })
                        }
                    })

    完美是吧,测试上线,继续喝咖啡。

    三个月后。。。。。

    有些顾客反应,点击提交后,有时没有提交成功,老板这时大发雷霆,这已经是第二次出现这样的失误了。

    是的,只调用一次,但是鬼知道它会不会调用一次?

    这里问题的本质是什么?

    它就是所谓的回调地域。

    我们总是有很多的回调函数需要交给第三方工具处理,类似于$.ajax,jquery就一定是值得信任的?图样图森破!你永远不知道jquery下面可能还埋着上一位开发者给你准备的周年大礼包。最糟糕的是,这个第三方工具你没有修改的能力,要么你换掉他,要么你解密,要么换版本,谁知道作者会不会继续更新?

    把我们的回调交给不受信任的第三方程序,这就是回调地域,可怕的很!

    Promise调用方式

      今天的主角是promise。它可以让我们的回调变得promise。 

    试想,我们把上述的ajax再次封装(在不能改动源代码的情况下),可能代码如下:

     var then = function(resolve,reject,timeout){
                    var a = 0;
                    $("btn").on("click",function(){
                        if($(this).hasClass("no-submit")){
                            $(this).removeClass("no-submit");
                            //忽略
                            $.ajax({
                                url:"....",
                                type:"json",
                                success:function(){
                                    a==0&&resolve();
                                    a++;
                                },
                                error:function(){
                                   a==0&&reject();
                                   a++;
                                }
                            })
                        }
                    })
                    if(new Date.now()>timeout){
                       a==0&&reject();
                       a++;
                    }
                }
                var a = 0;

    ok,我只是将前面的代码封装到一个叫then的函数里,这个函数需要三个参数,resolve(解决),reject(拒绝),以及一个超时时间,另外控制调用次数的变量a也有保留。

    有什么不同?

    不同之处在于,then函数是可信任的,至少现在我们可以确定,它要么被resolve,要么reject,绝不可能出现调用两次,或者不调用的情况。这种封装可以叫做控制反转,

    我们将原本给到$.ajax的回调权再次交回自己手中,上面的代码调用起来是这样的:

    then(function(){
        submit()
    },function(){
        error()
    })

    ok,我们只解决了其中的一些问题,重复调用,不调用,但还有更多的问题。

    让promise登场吧!

    使用promise封装上面代码:

     function request(){
                return new Promise(function(resolve,reject){
                    $.ajax({
                        url:"....",
                        type:"json",
                        success:function(){
                            resolve()
                        },
                        error:function(){
                           reject()
                        }
                    })
                })
            }
           request.then(function(){
                submit();
           },function(){
                error();
           })

    ok,是否豁然开朗?

    promise就是解决关于异步回调信任,顺便缓解了回调金字塔(一堆回调嵌套在一起,就是一个回调金字塔)问题的解决方案。

    在这个Promise构造函数中传入一个函数,这个函数有两个值,resolve、reject。一旦代码请求成功,resolve被调用,决议完成并忽略后面的所有调用。或者失败后决议被拒绝,调用reject。

    决议、解决、拒绝术语

      一个promise通常有三种状态  pending(进行中)、fulfilled(已成功)和rejected(已失败)。

    可以说在任何情况下,一个promise只有一个决议。 它只可能是fulfilled或者rejected其中一种,并且是不可以逆转的。意思是你无法让一个已经被拒绝的promise回滚。它永远都会有一个确定的回复。

       

    Promise API

      promise.all(Array);

       Promise.all方法用于将多个 Promise 实例,包装成一个新的 Promise 实例,并且这个新的promise返回的最终值是传入的多个Promise决议完成的值。

       有了Promise.all方法,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加简单易懂。

        像这样的调用:

     Promise.all([request("url1"),request("url2")]).then((result)=>{
          console.log(result) //[url1result,url2result]
    })

        注意传入的顺序,数组promise决议的值与返回的result数组位置是一致的。对于以往的回调方式来说,这是很强大的api。

      

      Promise.race(array)

        这个方法和all调用方式一样,但是决议的方式不一样,.all等待所有决议完成新的 Promise返回决议。 而.race,一旦有某个promise决议完成,其余的会立刻终止。也就是说它只会执行最快的那个promise。

       

         ...更多api可以查看阮大大的es6教程

    结束

      promise已经成为主流。我在这里只讲了一些浅见,至于更多的用法,与君共勉!

  • 相关阅读:
    jsp页面间传递参数 中文乱码问题(zz)
    java 生成xml
    java dom4j 解析xml
    生成不重复的32为随机码
    [HYSBZ
    七夕祭
    [CF741D] Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    Baltic2014 sequence
    [洛谷P2459] SDOI2011 消耗战
    [洛谷P4172] WC2006 水管局长
  • 原文地址:https://www.cnblogs.com/ztfjs/p/promise2.html
Copyright © 2020-2023  润新知