wenjinhua / my-blog

有关工作学习的知识点总结
3 stars 0 forks source link

精读:实现一个promise #1

Open wenjinhua opened 4 years ago

wenjinhua commented 4 years ago

@TOC

先导:promise的使用

var p=new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve("success")
    },1000);
    console.log("create promise");
})
p.then(function(x){
    console.log(x);
})

1. 三个要点

promise.then(onFulfilled,onRejected)

其中onFulfilled方法表示状态从pending——>fulfilled(resolved)时所执行的方法,而onRejected表示状态从pending——>rejected所执行的方法。

myPromise.prototype.then=function(onFullfilled,onRejected){//3.then方法为什么要写在原型上? let self=this;//4.此处的this和构造函数中的this为什么指向是一样的? switch(self.status){ case "resolved": onFullfilled(self.value); break; case "rejected": onRejected(self.reason); break; default:
} }

针对注释中的疑问点:
- 为什么要用self来获取this?直接用this不可以吗?(**this作用域问题**)
    直接用this可能导致this指代错误
- value和reason不可以用同一个变量吗?
经测试,可以将成功信息和失败信息使用同一个变量存储,即将存储在reason的值也存储在value上。
- then方法为什么要写在原型上?(**原型上和构造函数上的方法**)
为了能让实例对象调用then方法,可以将其写在两处:
(1)写在构造函数里
(2)写在原型上
由于写在构造函数上时,会在每个实例上都克隆这个方法。而定义在原型上的方法,实例对象则会共享这个方法
- then方法的this和构造函数中的this为什么指向是一样的?(**this作用域问题**)
(1)构造函数中的this指向的是new出来的实例对象
(2)then方法中的this指向的是调用者,也是new出来的实例对象。

## 2.v2.0基于观察模式实现
大致思路如下:
1、针对V1.0中不能处理异步执行的resolve和reject。
2、采用观察者模式,将回调函数进行存储,当状态发生变化时,即可执行
```javascript
function myPromise(constructor){
    let self=this;
    self.status="pending" 
    self.value=undefined;
    self.reason=undefined;
    //新增加
    self.onFullfilledArray=[];
    self.onRejectedArray=[];
    //end
    function resolve(value){
       if(self.status==="pending"){
          self.value=value;
          self.status="resolved";
          //新增加
          console.log('555555555555')
          self.onFullfilledArray.forEach(function(f){
                f(self.value);
          });
          //end
       }
    }
    function reject(reason){
       if(self.status==="pending"){
          self.reason=reason;
          self.status="rejected";
          //新增加
          self.onRejectedArray.forEach(function(f){
              f(self.reason);
          })
          //end
       }
    }
    try{
       constructor(resolve,reject);
    }catch(e){
       reject(e);
    }
}

myPromise.prototype.then=function(onFullfilled,onRejected){
   let self=this;
   switch(self.status){
      //新增加
      console.log('self.status...', self.status);
      case "pending":
        self.onFullfilledArray.push(function(){
             onFullfilled(self.value)
        });
        self.onRejectedArray.push(function(){
             onRejected(self.reason)
        });
      //end
      case "resolved":
        onFullfilled(self.value);
        break;
      case "rejected":
        onRejected(self.reason);
        break;
      default:       
   }
}

疑问点: 1、为什么要在resolve和reject中执行回调,而不是在then函数中执行? 我理解的执行回调的一个基本时间点是:status在哪个地方由pending变为resolved和rejected

var p=new myPromise(function(resolve,reject){
    setTimeout(function(){
        resolve("2222222222")
    },1000);
});
p.then(function(x){
    console.log(x);
}, function(y){
    console.log(y)
})

执行的顺序:

  1. 创建myPromise实例
  2. 执行p.then(此时status为pending,所以讲回调函数添加到数组中)
  3. 执行settimeout中的resolve('22222222')
  4. 在resolve中执行数组中的回调函数

所以如果还是按照1.0版本的myPromise,会导致then中的回调函数不执行,因为在执行then函数时的status是pending,不匹配任何case。

2、按照2.0的方式,相当于在两个地方都执行了then中的回调函数,这样会不会导致回调函数执行两遍? 不会,因为在then中,只有case为pending时,才把回调函数push到数组里,其他情况,数组为空。

3. v3.0then方法实现链式调用

具体思路:then方法实现链式调用的前提时,then方法的返回值也是一个promise。(将2.0中的then方法的每一个case都用myPromise封装)

myPromise.prototype.then=function(onFullfilled,onRejected){
    let self=this;
    let promise2;
    switch(self.status){
      case "pending":
        promise2=new myPromise(function(resolve,reject){
             self.onFullfilledArray.push(function(){
                try{
                   let temple=onFullfilled(self.value);
                   resolve(temple)
                }catch(e){
                   reject(e) //error catch
                }
             });
             self.onRejectedArray.push(function(){
                 try{
                   let temple=onRejected(self.reason);
                   reject(temple)
                 }catch(e){
                   reject(e)// error catch
                 }
             });
        })
      case "resolved":
        promise2=new myPromise(function(resolve,reject){
            try{
              let temple=onFullfilled(self.value);
              //将上次一then里面的方法传递进下一个Promise的状态
              resolve(temple);
            }catch(e){
              reject(e);//error catch
            }
        })
        break;
      case "rejected":
        promise2=new myPromise(function(resolve,reject){
            try{
               let temple=onRejected(self.reason);
               //将then里面的方法传递到下一个Promise的状态里
               resolve(temple);   
            }catch(e){
               reject(e);
            }
        })
        break;
      default:       
   }
   return promise2;
}