11.手写封装 promise, 模拟 promise 源码2

"Hello World, Hello Blog"

Posted by wudimingwo on December 15, 2018

丁老师学习名言 你用你会的知识去解释他, => 解释通了, 你就明白了 => 解释不通, 该学习了!!

继续..

step1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
constructor () {
...
用来存放then中的回调
this.resoveCB = null;
this.rejectCB = null;
}

...
then (resolveFn,rejectFn) {
...
              if (this.state == "pending") {
              	return new myPromise((resolve, reject) => {
              	  this.resolveCB = ((resolveFn)=>{
              	    return () => {
              	      var res = resolveFn(this.data);
              	    }
              	  })(resolveFn);
              	})
              }

}

从这里开始就烧脑了,,, 首先我们需要在 ‘pending’ 时先返回一个对象, 我们需要在 this.resolveCB中存一下函数resolveFn 但我们还需要把相应的参数也放进去 所以套了一层 函数绑定参数.

step2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
              if (this.state == "pending") {
              	return new myPromise((resolve, reject) => {
              	  this.resolveCB = ((resolveFn)=>{
              	    return () => {
              	      var res = resolveFn(this.data);
              	      if (res instanceof myPromise) {
              	      	res.then(resolve,reject);
              	      } else{
              	      	resolve(res)
              	      }
              	    }
              	  })(resolveFn);
              	})
              }

刚开始确实是没看懂, 跟着执行顺序捋了一遍, 为什么这个逻辑成立是理解了. 因为pending 所以我们用this.resolveCB 来存了一下 函数, 返回了一个新的中间promise对象, 当前一个promise对象有了状态的变化时, 这个对象也要跟着改变对象, 如果有new了一个新的 new Promise对象, 就需要在这个new Promise对象的 状态改变时, 把中间的promise状态改变, 这样才能触发 保存的函数? 这里回头再思考

step3 补齐一下rejiect 这边

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
              if (this.state == "pending") {
              	return new myPromise((resolve, reject) => {
              	  this.resolveCB = ((resolveFn)=>{
              	    return () => {
              	      var res = resolveFn(this.data);
              	      if (res instanceof myPromise) {
              	      	res.then(resolve,reject);
              	      } else{
              	      	resolve(res)
              	      }
              	    }
              	  })(resolveFn);
              	  
              	  this.rejectCB = ((rejectFn)=>{
              	    return () => {
              	      var res = rejectFn(this.data);
              	      if (res instanceof myPromise) {
              	      	res.then(resolve,reject);
              	      } else{
              	      	resolve(res)
              	      }
              	    }
              	  })(rejectFn);
              	})
              }

有一个地方我有点懵逼, 或者之前我理解有错误. 我以为promise 的后序then中 只要有一次进入 resolve 之后的都会进入resolve 有一次进入 reject 之后的都会进入rejiect 但老师写的reject 里 向下传递的状态是 resolve 也就是说 reject 线路还会回到 resolve?

测试 ``` let P = new Promise((res,rej) => {

rej(123) }).then(null,(data) => { console.log(data); return 223 }).then(null,(data) => { console.log(data); })// 按我之前的理解, 应该是返回223 但没有

let P = new Promise((res,rej) => {

rej(123) }).then(null,(data) => { console.log(data); return 223 }).then((data) => { console.log(data); })// 返回了223

1
2
3
4
5
6
> 这要怎么理解呢?
> 也就是说默认then 执行过后返回的promise对象的状态都是 resolved 
> 除非回调中返回的是新的 promise 对象.

step4
为了一下这种情况

let p = new myPromise((res,rej) => { rej(123) })

p.then(null,(data) => {console.log(data + 200)}); p.then(null,(data) => {console.log(data)});

1

constructor(){ …

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
          this.resolveCB = [];
          this.rejectCB = [];
          
          let resolve = (data) => {
            if (this.state == "pending") {
              this.state = "resolved"
              this.data = data;
              this.resolveCB.forEach(fn => fn());
            }
          }
          let reject = (data) => {
            if (this.state == "pending") {
              this.state = "rejected"
              this.data = data;
              this.rejectCB.forEach(fn => fn());
            }
          } } ... then(resolveFn,rejectFn){ ...

          if (this.state == "pending") {
          	return new myPromise((resolve, reject) => {
          	  this.resolveCB.push((resolveFn)=>{
          	    return () => {
          	      var res = resolveFn(this.data);
          	      if (res instanceof myPromise) {
          	      	res.then(resolve,reject);
          	      } else{
          	      	resolve(res)
          	      }
          	    }
          	  })(resolveFn);
          	  
          	  this.rejectCB.push((rejectFn)=>{
          	    return () => {
          	      var res = rejectFn(this.data);
          	      if (res instanceof myPromise) {
          	      	res.then(resolve,reject);
          	      } else{
          	      	resolve(res)
          	      }
          	    }
          	  })(rejectFn);
          	})
          } }
1
2
step5 
让所有同步操作都变成异步?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
          let resolve = (data) => {
            if (this.state == "pending") {
              setTimeout(() => {
                
              this.state = "resolved"
              this.data = data;
              this.resolveCB.forEach(fn => fn());
              },0)
            }
          }
          let reject = (data) => {
            if (this.state == "pending") {
              setTimeout(() => {
                
              this.state = "rejected"
              this.data = data;
              this.rejectCB.forEach(fn => fn());
              },0)
            }
          } ``` 贴一下完整版 ``` class myPromise {
        constructor (fn) {
          if (typeof fn !== "function") {
            throw TypeError(`myPromise resolver ${fn} is not a function`)
          }
          this.state = "pending";
          this.data = undefined;
          
          this.resolveCB = [];
          this.rejectCB = [];
          
          let resolve = (data) => {
            if (this.state == "pending") {
              setTimeout(() => {
                
              this.state = "resolved"
              this.data = data;
              this.resolveCB.forEach(fn => fn());
              },0)
            }
          }
          let reject = (data) => {
            if (this.state == "pending") {
              setTimeout(() => {
                
              this.state = "rejected"
              this.data = data;
              this.rejectCB.forEach(fn => fn());
              },0)
            }
          }
          
          fn(resolve,reject);
        }
        then (resolveFn, rejectFn) {
          if (this.state == "resolved") {
            let rus = resolveFn(this.data);
            if (rus instanceof myPromise) {
              return rus
            }else{
              return myPromise.resolve(rus);
            }
          }
          if (this.state == "rejected") {
            let rus = rejectFn(this.data);
            if (rus instanceof myPromise) {
            return rus
          }else{
            return myPromise.resolve(rus);
          }
          }
          
          if (this.state == "pending") {
          	return new myPromise((resolve, reject) => {
          	  console.log(this.resolveCB);
          	  this.resolveCB.push(((resolveFn)=>{
          	    return () => {
          	      var res = resolveFn(this.data);
          	      if (res instanceof myPromise) {
          	      	res.then(resolve,reject);
          	      } else{
          	      	resolve(res)
          	      }
          	    }
          	  })(resolveFn));
          	  
          	  this.rejectCB.push(((rejectFn)=>{
          	    return () => {
          	      var res = rejectFn(this.data);
          	      if (res instanceof myPromise) {
          	      	res.then(resolve,reject);
          	      } else{
          	      	resolve(res)
          	      }
          	    }
          	  })(rejectFn));
          	})
          }
        } 
        static resolve (data) {
          return new myPromise((suc) => {
            suc(data);
          })
        }
        static reject (data) {
         return new myPromise((suc,err) => {
          err(data);
        })
        }
    } ```

思考 实际上到昨天的同步处理为止,都是比较简单的. 到了要解决异步问题的时候, 我们发现必须要先返回一个对象, 并且要把函数先保存下来. 问题还在于, 我们要进行链式调用, 在明确每次then返回的对象都不相同时, 我们要解决一个问题就是,对象间的传递. 传递状态, 传递数据, 传递函数? 昨天我写得异常暴力版本,主要就是想不通怎么传递, 因为传递状态和数据的接口已经写好了, 理论上就应该用这两个接口 但这两个接口貌似只能在 new 新对象的时候才能传.

我们看一下就会发现, 丁老师的版本是怎么传的呢? 他确实是先返回了一个对象, 也是存了函数, 最核心的就是开篇讲的, 他在存函数的时候, 用函数的多层嵌套的方式, 把数据和函数一起绑定之后的函数放进了数组里. 然后在这个函数中调用各个接口,完成三个对象之间的状态,数据的传递. 当然我觉得我还是很难想到,但比刚开始好多了.

这应该是最近看到的代码中最漂亮的代码了.