# 实现promise

Promise是ES6中的新的异步语法, 解决了回调嵌套的问题:

    new Promise((resolve) => {
      setTimeout(()=> {
        resolve(1)
      },1000)
    }).then(val => {
      console.log(val)
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(2)
        },1000)
      })
    }).then(val => {
      console.log(val)
    })
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 1.实现状态切换

  • promise实例有三个状态, pending, fulfilled, rejected

  • promise实例在构造是可以传入执行函数, 执行函数有两个形参 resolve, reject可以改变peomise的状态

    promise的状态一旦改变不可再进行改变

  • 执行函数会再创建promise实例时, 同步执行

      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          const resolve = (value) => {
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
            }
          };
          executor(resolve, reject);
        }
      }

      let p = new MyPromise((resolve, reject) => {
        resolve(1);
      });
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

# 2.实现then异步执行

promise实例可以调用then方法并且传入回调

如果调用then时, Promise实例是 fulfilled 状态, 则马上异步执行传入的回调

如果调用then时, Promise实例是pending状态, 传入的回调会等到resolve后再异步执行

例子:

    let p = new Promise((resolve, reject) => {
      console.log(1)
      resolve(2)
      console.log(3)
    })
    p.then((val) => {
      console.log(val)
    })

    // 执行顺序 1 3 2
1
2
3
4
5
6
7
8
9
10
    let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(1)
      },2000)
    })
    p1.then(val => {
      console.log(val)
    })
1
2
3
4
5
6
7
8

思路: 需要用回调先保存到队列中, 在resolve后异步执行队列里的回调, 在then时判断实例的状态再决定是将回调推入队列, 还是直接异步执行回调:

      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          this.onFulfilledCallbacks = []; // 成功的回调队列
          this.onRejectedCallbacks = []; // 失败的回调队列
          const resolve = (value) => {
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
              setTimeout(() => {
                this.onFulfilledCallbacks.forEach((callback) => {
                  callback(this.value);
                });
              });
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              setTimeout(() => {
                this.onRejectedCallbacks.forEach((callback) => {
                  callback(this.reason);
                });
              });
            }
          };
          executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
          if (this.status === FULFILLED) {
            setTimeout(() => {
              onFulfilled(this.value);
            });
          }
          if (this.status == REJECTED) {
            setTimeout(() => {
              onRejected(this.reason);
            });
          }
          if (this.status === PENDING) {
            this.onFulfilledCallbacks.push(onFulfilled);
            this.onRejectedCallbacks.push(onRejected);
          }
        }
      }
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

# 3.resove Promise实例的情况

resolve的值有可能也是个promise实例, 这时候就要用前述实例自己resolve的值

    let p = new Promise((resolve, reject) => {
      resolve(new Promise((resolve2, reject2) => {
        setTimeout(() => {
          resolve2(1)
        })
      }))
    })
    p.then(val => {
      console.log(val)
    })
1
2
3
4
5
6
7
8
9
10

因此需要在promise1 的 resolve 函数中进行判断, 是promise实例则在这个promise实例(promise2) 后接一个then, 并且将promise的resolve作为回调传入promise2的then

      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          this.onFulfilledCallbacks = []; // 成功的回调队列
          this.onRejectedCallbacks = []; // 失败的回调队列
          const resolve = (value) => {
            if(value instanceof this.constructor) {  // ⭐⭐⭐
              value.then(resolve,reject)
              return
            }
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
              setTimeout(() => {
                this.onFulfilledCallbacks.forEach((callback) => {
                  callback(this.value);
                });
              });
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              setTimeout(() => {
                this.onRejectedCallbacks.forEach((callback) => {
                  callback(this.reason);
                });
              });
            }
          };
          executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
          if (this.status === FULFILLED) {
            setTimeout(() => {
              onFulfilled(this.value);
            });
          }
          if (this.status == REJECTED) {
            setTimeout(() => {
              onRejected(this.reason);
            });
          }
          if (this.status === PENDING) {
            this.onFulfilledCallbacks.push(onFulfilled);
            this.onRejectedCallbacks.push(onRejected);
          }
        }
      }
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

# 4.实现链式调用

then可以链式调用, 而且前一个then的回调的返回值, 如果不是promise实例, 则下一个then回调的参数值就是上一个then回调的返回值, 如果是promise实例, 则下一个then回调的传参值, 是上一个then回调返回的promise实例的解决值(value)

      let p = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(1);
        }, 1000);
      });
      p.then(val => {
        console.log(val)
        return new Promise((resolve) => {
          setTimeout(()=> {
            resolve(2)
          },1000)
        })
      }).then(val => {
        console.log(val)
        return 3
      }).then(val => {
        console.log(val)
      })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

既然能够链式调用, 那么then方法本身的返回值必定是一个promise实例. 那么返回的promise实例是不是自身呢? 答案显而易见: 不是. 如果是一个promise的then方法的返回值是promise自身, 在new一个Promise时, 调用了resolve方法,. 因为promise的状态一旦更改便不能再次更改, 那么下面的所有then便只能执行成功的回调, 无法进行错误处理, 这显然并不符合promise的规范和设计promise的初衷.

因此 then方法会返回一个新的promise实例

      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          this.onFulfilledCallbacks = []; // 成功的回调队列
          this.onRejectedCallbacks = []; // 失败的回调队列
          const resolve = (value) => {
            if (value instanceof this.constructor) {
              value.then(resolve, reject);
              return;
            }
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
              setTimeout(() => {
                this.onFulfilledCallbacks.forEach((callback) => {
                  callback(this.value);
                });
              });
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              setTimeout(() => {
                this.onRejectedCallbacks.forEach((callback) => {
                  callback(this.reason);
                });
              });
            }
          };
          executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
          const p2 = new this.constructor((resolve, reject) => {
            if (this.status === FULFILLED) {
              setTimeout(() => {
                try {
                  let callbackvalue = onFulfilled(this.value);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
            if (this.status == REJECTED) {
              setTimeout(() => {
                try {
                  let callbackvalue = onRejected(this.reason);
                  resolve(callbackvalue)
                } catch (error) {
                  reject(error)
                }
              });
            }
            if (this.status === PENDING) {
              this.onFulfilledCallbacks.push(() => {
                try {
                  let callbackvalue = onFulfilled(this.value)
                  resolve(callbackvalue)
                }catch(error) {
                  reject(error)
                }
              });
              this.onRejectedCallbacks.push(() => {
                try {
                  let callbackvalue = onRejected(this.reason)
                  resolve(callbackvalue)
                }catch(error) {
                  reject(error)
                }
              });
            }
          });
          return p2;
        }
      }
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

# 5.实现其他方法

  • catch
  • resolve
  • reject
  • all
  • race
      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        static resolve(value) {
          if (value instanceof this) {
            return value;
          }
          return new this((resolve, reject) => {
            resolve(value);
          });
        }
        static reject(reason) {
          return new this((resolve, reject) => {
            reject(reason);
          });
        }
        static all(promises) {
          return new this((resolve, reject) => {
            let promiseNum = promises.length;
            let resovedNum = 0;
            let resolveValues = new Array(promiseNum);
            for (let i = 0; i < promiseNum; i++) {
              this.resolve(promises[i]).then((val) => {
                resovedNum++;
                resolveValues[i] = val;
                if (resovedNum === promiseNum) {
                  // 所有的promise都已经解决
                  resolve(resolveValues);
                }
              }),
                (reason) => {
                  reject(reason);
                };
            }
          });
        }
        static race(promises) {
          return new this((resolve, reject) => {
            let length = promises.length;
            for (let i = 0; i < length; i++) {
              this.resolve(promises[i]).then(
                (value) => {
                  resolve(value);
                },
                (reason) => {
                  reject(reason);
                }
              );
            }
          });
        }
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          this.onFulfilledCallbacks = []; // 成功的回调队列
          this.onRejectedCallbacks = []; // 失败的回调队列
          const resolve = (value) => {
            if (value instanceof this.constructor) {
              value.then(resolve, reject);
              return;
            }
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
              setTimeout(() => {
                this.onFulfilledCallbacks.forEach((callback) => {
                  callback(this.value);
                });
              });
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              setTimeout(() => {
                this.onRejectedCallbacks.forEach((callback) => {
                  callback(this.reason);
                });
              });
            }
          };
          executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
          const p2 = new this.constructor((resolve, reject) => {
            if (this.status === FULFILLED) {
              setTimeout(() => {
                try {
                  let callbackvalue = onFulfilled(this.value);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
            if (this.status == REJECTED) {
              setTimeout(() => {
                try {
                  let callbackvalue = onRejected(this.reason);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
            if (this.status === PENDING) {
              this.onFulfilledCallbacks.push(() => {
                try {
                  let callbackvalue = onFulfilled(this.value);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
              this.onRejectedCallbacks.push(() => {
                try {
                  let callbackvalue = onRejected(this.reason);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
          });
          return p2;
        }
        catch(onRejected) {
          return this.then(null, onRejected);
        }
      }

      let p = MyPromise.race([
        new MyPromise((resolve) => {
          setTimeout(() => {
            resolve(1);
          }, 1000);
        }),
        new MyPromise((resolve) => {
          setTimeout(() => {
            resolve(2);
          }, 2000);
        }),
        new MyPromise((resolve) => {
          setTimeout(() => {
            resolve(3);
          }, 3000);
        }),
      ]);
      p.then((val) => {
        console.log(val);
      });
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

# 6.macrotask和microtask

所谓macroTask (宏任务) 是指将任务排到下一个事件循环, microTask (微任务) 是指将任务排到当前事件循环的队尾, 执行时机会比宏任务更早. Promise的标准里没有规定Promise里的异步该使用哪种, 但在node和浏览器的实现里都是使用的miroTask (微任务)

    setTimeout(()=>{
      console.log(1)
    },0)
    let p = Promise.resolve(2)
    p.then(val => {
      console.log(val)
    })
    // 执行顺序 2  1
1
2
3
4
5
6
7
8

宏任务api包括: setTimeout, setInterval, setImmediate(Node), requestAnimationFrame(浏览器), 各种IO操作, 网络请求

微任务api包括: process.nextTick(Node), Mutationobserver(浏览器)

# 7.实现微任务

      let nextTick = (function () {
        let callbacks = [];
        let counter = 1;
        function handler() {
          let copy = callbacks.slice();
          callbacks = [];
          copy.forEach((cb) => {
            cb();
          });
        }
        let node = document.createElement("div");
        let observer = new MutationObserver(handler);
        observer.observe(node, {
          childList: true,
        });
        return function (cb) {
          callbacks.push(cb);
          // 触发mutationObserver
          counter = (counter + 1) % 2;
          node.innerHTML = counter;
        };
      })();
      const PENDING = "pending";
      const FULFILLED = "fulfilled";
      const REJECTED = "rejected";
      class MyPromise {
        static resolve(value) {
          if (value instanceof this) {
            return value;
          }
          return new this((resolve, reject) => {
            resolve(value);
          });
        }
        static reject(reason) {
          return new this((resolve, reject) => {
            reject(reason);
          });
        }
        static all(promises) {
          return new this((resolve, reject) => {
            let promiseNum = promises.length;
            let resovedNum = 0;
            let resolveValues = new Array(promiseNum);
            for (let i = 0; i < promiseNum; i++) {
              this.resolve(promises[i]).then((val) => {
                resovedNum++;
                resolveValues[i] = val;
                if (resovedNum === promiseNum) {
                  // 所有的promise都已经解决
                  resolve(resolveValues);
                }
              }),
                (reason) => {
                  reject(reason);
                };
            }
          });
        }
        static race(promises) {
          return new this((resolve, reject) => {
            let length = promises.length;
            for (let i = 0; i < length; i++) {
              this.resolve(promises[i]).then(
                (value) => {
                  resolve(value);
                },
                (reason) => {
                  reject(reason);
                }
              );
            }
          });
        }
        constructor(executor) {
          this.status = PENDING;
          this.value = null;
          this.reason = null;
          this.onFulfilledCallbacks = []; // 成功的回调队列
          this.onRejectedCallbacks = []; // 失败的回调队列
          const resolve = (value) => {
            if (value instanceof this.constructor) {
              value.then(resolve, reject);
              return;
            }
            if (this.status === PENDING) {
              this.status = FULFILLED;
              this.value = value;
              nextTick(() => {
                this.onFulfilledCallbacks.forEach((callback) => {
                  callback(this.value);
                });
              });
            }
          };
          const reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              nextTick(() => {
                this.onRejectedCallbacks.forEach((callback) => {
                  callback(this.reason);
                });
              });
            }
          };
          executor(resolve, reject);
        }
        then(onFulfilled, onRejected) {
          const p2 = new this.constructor((resolve, reject) => {
            if (this.status === FULFILLED) {
              nextTick(() => {
                try {
                  let callbackvalue = onFulfilled(this.value);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
            if (this.status == REJECTED) {
              nextTick(() => {
                try {
                  let callbackvalue = onRejected(this.reason);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
            if (this.status === PENDING) {
              this.onFulfilledCallbacks.push(() => {
                try {
                  let callbackvalue = onFulfilled(this.value);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
              this.onRejectedCallbacks.push(() => {
                try {
                  let callbackvalue = onRejected(this.reason);
                  resolve(callbackvalue);
                } catch (error) {
                  reject(error);
                }
              });
            }
          });
          return p2;
        }
        catch(onRejected) {
          return this.then(null, onRejected);
        }
      }

      setTimeout(() => {
        console.log(1);
      }, 0);
      let p = MyPromise.resolve(2);
      p.then((val) => {
        console.log(val);
      });
      // 执行顺序 2  1
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
上次更新: 2020/11/24 下午2:27:13