zoukankan      html  css  js  c++  java
  • 原生JS实现Promise

      ES6中Promise可以说很大情况下改善了异步回调的嵌套问题,那么如果我们自己去写一个类似Promise的库应该怎么去写?

      我们先看一下Promise的特点:

      第一:Promise构造函数接受一个函数作为参数,函数里面有两个参数resolve和reject分别作为执行成功或者执行失败的函数

    var promise=new Promsie(function(resolve,rejec){
        if(/*异步执行成功*/){
            resolve(value);
        }else{
            reject(error);
        }
    })

      第二:可以通过then设置操作成功之后的操作,接受两个函数作为参数

    .then(function(){
        //回调执行成功之后的操作
    },function(){
        //回调执行失败之后的操作,可以没有
    });

      那么原生js实现以上特点应该比较简单了

    function PromiseM(){
        this.status='pending';
        this.msg='';
        var process=arguments[0];
        var that=this;
        process(function(){
            that.status='resolve';
            that.msg=arguments[0];
        },function(){
            that.status='reject';     
            that.msg=arguments[0];           
        });
        return this;
    }
    PromiseM.prototype.then=function(){
        if(this.status=='resolve'){
            arguments[0](this.msg);
        }
        if(this.status=='reject'&&arguments[1]){
            arguments[1](this.msg);
        }
    }
    //测试用例
    var mm=new PromiseM(function(resolve,reject){
        resolve('123');//123其实就是第二个arguments[0]
    });//上面的第一个arguments[0]
    mm.then(function(success){
        console.log(success);//该success其实就是上面的this.msg
        console.log("ok!");
    },function(){
        console.log('fail!');
    });
    //123
    //ok

      以上只是最基本的实现,在代码结构结构和容错方面没有进行考虑。

      对ES6里promise对象以及异步机制的理解

      我现在声明一个a,并且要延时1秒钟后给他赋值为10,然后打印这个a:

    var a;
    setTimeout(function (){
        a = 10;
    },1000);//1000ms后给a赋值为10
    console.log(a)//undefined,

      很显然,a是undefined,因为js是非阻塞的,它不会等你定时器里的东西走完了,再执行打印a这个操作。它不等你读完,就会迫不及待地去打印a,因为a要1秒后才能被赋值,所以此时a只是个undefined。

      那怎么办?很简单,把打印a这个操作也放进延时定时器里嘛,我想这个例子并不难理解,那么接下来我会试图将其功能进行拓展,打印a这个需求我并不需要,我想要用a做其他事情,比如让他乘以2并输出返回结果,或者其他的涉及到a的操作。那很简单,我将console.log(a)这段代码删去,封装成一个函数,并将其作为参数传进这个定时器里,也就是所谓的“回调函数”如下:

    var a;
    function foo(callBack){
        setTimeout(function (){
        a = 10;     callBack
    &&callBack()   },1000) } foo(function (){ //因为a是全局的,所以不需要将a传参进foo的回调中   return a*2 })

      调用foo的时候,作为参数的这个匿名函数,就是所谓的回调函数,回调函数这个机制极大地增加了代码的可能性,你可以在回调中做任何事,并且在不同的地方进行调用,你也将得到不同的反馈,如果将一个函数执行过程看成一个时间轴,那回调函数就可以允许你在这个过程中的各个时刻内执行其他代码,例如你可以将Vue.js的生命周期钩子函数看成是不同时期的回调函数

      回调函数的作用显而易见,但如果一层回调套一层回调的话,代码极其不方便阅读与修改,因此ES6提供了Promise构造函数,从形式上改善了回调地狱。

    var a;
    var p = new Promise(function (resolve,reject){
      setTimeout(function (){
        a = 10;
        resolve();/*reject也就是失败时对应的函数,由于这个例子比较简单,就不再赘述,毕竟是面向新手的*/
      },1000)
    }).then(function (){
      console.log(a)
    })

      现在我们就以一个人起床后的行为为例来深入理解异步执行机制,来看代码:

    getup();
    wearClothes();
    brushTeeth();
    washFace();
    eatBreakfast();
    goToCompany();

      因为js是异步执行的,所以如果这么写,逻辑上等同于一个人同时开始做“起床+穿衣+刷牙+洗脸+吃早饭+出门上班”这些事,显然是不可能的事情,与我们想要的结果大相径庭,依照回调函数的写法,我们会在上述每个行为结束之后(即函数执行完毕的我们想要让他做什么,例如$.ajax()的success)传入一个回调函数,并将下一步的函数写进回调里,环环相扣,写法比较恶心,相当难以维护。

    var p = new Promise(function (resolve){
        getUp(function (){
            resolve();
        });
    }).then(function (){
        return new Promise(function (resolve){
            wearClothes(function (){
                resolve();
            });
        })
    }).then(function (){
        return new Promise(function (resolve){
            brushTeeth(function (){
                resolve();
            });
        })
    }).then(function (){
        return new Promise(function (resolve){
            washFace(function (){
                resolve();
            });
        })
    }).then(function (){
        return new Promise(function (resolve){
            eatBreakfast(function (){
                resolve();
            });
        })
    }).then(function (){
        goToCompany()
    })

      如果要链式调用then的话,必须要注意的一点是,一定要在then里的回调函数return一个新的promise对象,否则执行顺序将向上开始查找,直到找到最近的promise实例。

      写到这里大家会发现promise并没有改变什么,只是把异步代码的书写形式从水平方向改为了竖直方向,让代码更符合人类的阅读习惯

  • 相关阅读:
    gitlab + gitlab-runner 实现项目的自动化部署测试环境与打包
    docker 部署 zookeeper 集群
    CSS 使用id属性的规则
    SimpleXML使用详解
    PHP通用分页类
    MYSQL远程连接速度慢的解决方法
    远程连接mysql出现1045错误的解决办法
    Bootstrap 元素居中设置
    PHP 时间戳
    html代码/如何做到有横线无竖线的表格/或横线有颜色/竖线没颜色
  • 原文地址:https://www.cnblogs.com/goloving/p/9297308.html
Copyright © 2011-2022 走看看