Promise的理解-JavaScript

Posted 恒哥的爸爸

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise的理解-JavaScript相关的知识,希望对你有一定的参考价值。

1 为什么要使用Promise

防止回调黑洞
      例如,正常的ajax调用,程序员既要定义业务逻辑函数,还要控制这些业务逻辑执行的顺序,一旦异步调用嵌套太深,整个代码可读性和可维护度都会下降。

      例如,实际项目中有如下需求 0.登录 1.查用户配置,2.通过配置权限,查询可以浏览的数据,以上三步肯定是顺序执行的。如下就是直接采用回调方式来实现的代码,而且这里的代码,没有处理错误和异常。估计没几个人愿意看这么多括号的一大组逻辑。

function generalQuery()
	this.localVal = "hengebb";
  let param = 
      name:'hege',
      key:'001'
  
  var xhr = new XMLHttpRequest()  
  xhr.open('post', 'http://127.0.0.1:8080/ris/qcTest/lgin.api',JSON.stringify(param))
  xhr.send(null)
  xhr.onreadystatechange = ()=>
      if (xhr.readyState == 4 && xhr.status == 200) 
      		console.log("@2 local val ="+this.localVal)
          let ret = xhr.responseText
          let retObject = JSON.parse(ret);
          if(retObject.token == '0001')
              let param = 
                  token:'0001',
              
              var yhr = new XMLHttpRequest()
              yhr.open('post','http://127.0.0.1:8080/ris/qcTest/config.api', JSON.stringify(param))
              yhr.send(null)
              yhr.onreadystatechange = function()
              	console.log("@3 local val ="+this.localVal)
                if(yhr.readyState == 4 && yhr.status == 200)
                  let ret = yhr.responseText
                  let retObject = JSON.parse(ret);
                  if(retObject.config == 0)
                      let param =  
                          token:"0001",
                          config:1
                      
                      let zhr = new XMLHttpRequest()
                      zhr.open('post','http://127.0.0.1:8080/ris/qcTest/query.api', JSON.stringify(param))
                      zhr.send(null)
                      zhr.onreadystatechange = function()
                          if(zhr.readyState == 4 &&  zhr.status == 200)
                              let ret = yhr.responseText
                              let retObject = JSON.parse(ret);
                              console.log(retObject.msg)
                          
                      
                  
                
              
          
      
  

接下来,我们看Promise的处理方式

function login() 
  let param = 
     name:'hege',key:'001'
  
  return new Promise((resolve)=>
    // 需要在这里处理异步任务
    var xhr = new XMLHttpRequest();
    xhr.open('post','http://127.0.0.1:8080/ris/qcTest/lgin.api',JSON.stringify(param));
    xhr.send(null);
    xhr.onreadystatechange = function() 
      if(xhr.readyState == 4 && xhr.status == 200) 
        // 获取后台数据
        var ret = xhr.responseText;
        // 成功的情况
        resolve(ret);
      
    
  )



function config()
  let param = 
      token:'0001',
  
  return new Promise((resolve)=>
    var xhr = new XMLHttpRequest();
    xhr.open('post','http://127.0.0.1:8080/ris/qcTest/config.api',JSON.stringify(param));
    xhr.send(null);
    xhr.onreadystatechange = function() 
      if(xhr.readyState == 4 && xhr.status == 200) 
        // 获取后台数据
        var ret = xhr.responseText;
        // 成功的情况
        resolve(ret);
      
    
  )


function query()
	let param =  
	    token:"0001",
	    config:1
	
  return new Promise((resolve)=>
    var xhr = new XMLHttpRequest();
    xhr.open('post','http://127.0.0.1:8080/ris/qcTest/query.api',JSON.stringify(param));
    xhr.send(null);
    xhr.onreadystatechange = function() 
      if(xhr.readyState == 4 && xhr.status == 200) 
        // 获取后台数据
        var ret = xhr.responseText;
        // 成功的情况
        resolve(ret);
      
    
  )

定义完,每一步的操作后,执行代码如下

function promiseQuery()
	this.localVal = "hengebb";
	login().then(ret=>
	  return config();
	).then(ret=>
		console.log("@2 ==== this point "+this.localVal)
	  return query();
	).then(ret=>
	  console.log(ret.msg)
	)

2 Promise的实现原理

2.1 伪代码

function SelfPromise(fn) 
    console.log("1. 注册异步函数")
    this.value = null;
    this.callbacks = [];
    fn.call(this, this.resolve.bind(this))
    //因为调用resolve函数的位置,在客户端,为了把this指针从客户端改变为SelfPromise实例对象,这里使用了bind函数

//自定义函数的原型函数
SelfPromise.prototype = 
    constructor: SelfPromise,
    then: function(thenFunc) 
        console.log("3. 注册异步函数回调后,需要执行的函数")
        var obj = 
            onfulfilled: thenFunc
        
        this.callbacks.push(obj);
        console.log(this.callbacks)
    ,
    resolve: function(data)  
        this.value = data;
        this.callbacks.forEach(item =>  //类似执行一个函数链(职责链模式)
            let p = item.onfulfilled(this.value);
            console.log(this)
        );
    

//客户端代码调用
function customPromiseTest()
  this.promiseTestVal = 99
  let promise = new SelfPromise((resolve)=>   //1. 将需要异步执行的函数注册到SelfPromise实例中,此函数的格式必须是带有一个形参function(param)格式(这里是针对SelfPromise的)
      console.log("2. 执行异步函数.... ")       
     //2. 执行注册到SelfPromise实例中的函数. 查看源码,第一步将resolve的this指针指向SelfPromise实例对象;第二部,通过call调用,执行fn异步注册函数
      var param = 							              
          ref_fac_id:1031
      ;
      setTimeout(()=>
          console.log("异步回调开始...")
          let ret = 
              ret:1,name:"hege",token:"10088"
          
          resolve(ret)
      ,1000)
  ).then((ret)=>    //3. 将异步返回后,需要后续执行的函数也注册到Promise的类中,
    console.log("4. 回调过程调用在步骤3中注册的函数") 
    //4. 回调函数开始执行,在then调用时,注册的函数
    console.log(ret.name + ret.token + " this." + this.promiseTestVal)
    //使用()=>方式的函数,这种函数没有自己的构造器,所以,就没有this指针,就只能是用括号外部的this指针
  )

在以上的代码中,我做了一些注释。

          实际上,客户调用代码,首先将异步函数1和异步函数回调后,希望后续执行函数2,这两个函数注册到Promise中;Promise内部,含有一个类似包装器功能的函数resolve,用此函数后续调用一个函数链,这些函数链上的函数,就是通过then注册到内部的函数。
          这里需要注意的点,还有如下几个,resolve函数的this指针必须bind到Promise函数中,因为执行的时候,是在客户端代码块内执行的。
          另外,就是被注册函数最好都采用()=>方式,不要采用function的方式。 这样,在客户端的回调函数代码块中,就能直接使用客户端函数的this指针。

         本人将以上的代码都上传到资源内,大家感兴趣的可以下载测试!

以上是关于Promise的理解-JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

Promise的理解-JavaScript

JavaScript:理解Promise方法

JavaScript Promise理解

JavaScript Promise 的理解和使用

全面理解Javascript中Promise

彻底理解Javascript 中的 Promise