1. 初始结构
原生
1 2 3
   | let promise1 = new Promise((resolve, reject) => {    })
  | 
 
- 传入func,func的参数分别是resolve, reject
实现
 
1 2 3 4 5 6 7
   | class myPromise {   constructor(func) {     func(this.resolve, this.reject)   }   resolve(){}   reject(){} }
  | 
 
2. 状态
- 共有三种状态,分别是
- Pending
 
- Fulfilled
 
- Rejected
 
 
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | class MyPromise {     static PENDING = 'pending';     static FULFILLED = 'fulfilled';     static REJECTED = 'rejected';     constructor(func) {         this.status = MyPromise.PENDING;         func(this.resolve, this.reject);     }     resolve() {         if (this.status === MyPromise.PENDING) {             this.status = MyPromise.FULFILLED;         }     }     reject() {         if (this.status === MyPromise.PENDING) {             this.status = MyPromise.REJECTED;         }     } }
 
  | 
 
static关键字
static定义静态方法/静态属性
 
类相当于实例的原型,实例能够继承原型上的方法和属性;
 
加上static关键字,方法或者属性就不会被实例继承,需要通过类来调用。
 
执行
1 2 3
   | let promise1 = new MyPromise((resolve, reject) => {     resolve(); })
  | 
 

现象:报错Cannot read property ‘status’ of undefined
原因: 
首先,我们在创建新实例的时候确实绑定了this指向
 
但是,我们是在新实例被创建后再在外部环境下执行resolve方法的,我们可以在resolve打印一下this指向
 

可以看到,此时this指向undefined
解决办法:绑定this值,可以通过bind, 箭头函数。
1 2 3 4 5 6 7 8
   | class MyPromise { 		...     constructor(func) { 				....         func(this.resolve.bind(this), this.reject.bind(this));     } 		... }
  | 
 
很好,此时this指向对了。
3. 传参数
原生
- 原生的promise可以给resolve/reject回调传入参数,并且在then中可以接收到。
 
1 2 3
   | let promise1 = new Promise((resolve, reject) => {     resolve('42'); })
  | 
 
实现
- 在constructor构造函数中定义变量result,用来存储传进来的参数
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | class MyPromise { 		...     constructor(func) {       ...         this.result = null;       ...     }     resolve(result) {         if (this.status === MyPromise.PENDING) { 						...             this.result = result;         }     }     reject(result) {         if (this.status === MyPromise.PENDING) { 						...             this.result = result;         }     } }
  | 
 
4. then
原生
1 2 3 4 5 6 7
   | let promise1 = new Promise((resolve, reject) => {     resolve('42'); }) promise1.then(     result => { console.log(result) },     result => {console.log(result)} )
  | 
 
- 原生的then支持传入两个回调函数
 
- 但是只能执行其中一个回调函数,如果状态是fulfilled,执行第一个回调函数;否则,执行第二个回调函数
 
实现
- 定义then函数,传入两个回调函数
 
1 2 3 4 5 6 7 8 9 10 11
   | class MyPromise { 		....     then(onFulFILLED, onREJECTED) {         if (this.status === MyPromise.FULFILLED) {             onFulFILLED(this.result)         }         if (this.status === MyPromise.REJECTED) {             onREJECTED(this.result)         }     } }
  | 
 
5. 执行异常
异常一
原生
1 2 3 4 5 6 7 8 9
   | let promise1 = new Promise((resolve, reject) => {     throw new Error('执行异常') }) promise1.then(     result => { console.log(result) },     result => {console.log(result.message)} )
 
 
  | 
 
- 在new Promise时抛出错误,throw new Error(‘…’);在then中的第二个回调函数中可以catch到这个错误
 
实现
目前效果
同样的,我们可以在我们现有的实现代码中抛出相同异常,看看会发生什么?

解决办法
在构造函数中添加try…catch,如果没有错误就走正常的func,如果有错误就直接走reject方法
1 2 3 4 5 6 7 8 9 10 11 12 13
   | class MyPromise { 		...     constructor(func) {         this.status = MyPromise.PENDING;         this.result = null;         try {             func(this.resolve.bind(this), this.reject.bind(this));         } catch(err) {             this.reject(err)         }     } 		... }
  | 
 
执行

异常二
原生
- 原生Promise规定then里面的两个参数如果不是函数的话就要被忽略
 
1 2 3 4 5 6 7
   | let promise1 = new Promise((resolve, reject) => {     resolve('42') }) promise1.then(     undefined,     result => {console.log(result.message)} )
  | 
 
由于第一个参数传入的undefined,根据规定,这个参数被忽略。所以控制台没有任何输出
实现
目前效果
尝试在我们目前的实现代码中传入undefeind,是会报错的,如下图所示

解决办法
默认将onFulFILLED和onREJECTED处理成一个函数
1 2 3 4 5 6 7 8
   | class MyPromise {   ...     then(onFulFILLED, onREJECTED) {         onFulFILLED = typeof onFulFILLED === 'function' ? onFulFILLED : () => { };         onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }; 		...     } }
  | 
 
此时,就能和原生一样了,如果传入的参数不是函数的话,就忽略。
6. 异步
关注点一
原生
首先,我们先来了解一下原生Promise的执行机制。先来看一段代码:
1 2 3 4 5 6 7 8 9 10
   | console.log('1'); let promise1 = new Promise((resolve, reject) => {     console.log('2');     resolve('哈哈') }) promise1.then(     result => { console.log(result) },     result => {console.log(result.message)} ) console.log('3')
  | 
 
 这里关系到事件执行机制,不懂的可以去了解一下这方面的知识。
执行顺序如下:
可以看到,我们先执行同步任务,所以输出1,2,3;然后执行异步任务,输出哈哈;
实现
目前效果
让我们在目前的实现代码中执行该段代码,

和原生不一样呢,它并没有异步的feel~
解决办法
- 引入setTimeout让我们的Promise.then变成异步来模仿原生Promise的执行效果把~
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
   | class MyPromise { 		...     then(onFulFILLED, onREJECTED) { 				...         if (this.status === MyPromise.FULFILLED) {             setTimeout(() => {                 onFulFILLED(this.result)             });                      }         if (this.status === MyPromise.REJECTED) {             setTimeout(() => {                 onREJECTED(this.result)             });                      }     } }
  | 
 
- 还是执行上面的代码
 

哇唔~现在我们可以异步输出哈哈啦~
关注点二
原生
如果我们在new Promise中的resolve回调外面加入一个setTimeout呢?此时原生Promise的执行效果会是什么样的?
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | console.log('1'); let promise1 = new Promise((resolve, reject) => {     console.log('2');     setTimeout(() => {         console.log('4');         resolve('哈哈')         console.log('5')     }); }) promise1.then(     result => { console.log(result) },     result => {console.log(result.message)} ) console.log('3')
  | 
 
输出结果
实现
目前效果
让我们继续在实现代码中执行以上的代码看看输出顺序吧~

咦~哈哈哪里去了??
分析原因
“哈哈”没有被输出原因 -> then方法可能没有被执行 -> then方法中的状态可能没有被改变 -> 因此,让我们输出一下状态看看吧

在构造函数中,status有发生了变化,并且从pending -> fulfilled;
 
在then函数中,没有调用status === ‘fulfilled’的回调函数
- 在事件循环机制中,如果我们不考虑现有的微任务的执行机制,单纯从代码来看,promise1.then方法的执行会早于setTimeout;也就是在resolve执行之前即status还没有发生变化的时候,就执行的then方法。
 
- 我们可以通过在实现代码的then方法中输出一下,就可以看到执行顺序
 
1 2 3 4 5 6 7 8
   | 1 2 执行了then方法,此时的status状态为 pending 3 pending 4 fulfilled 5
   | 
 
- 所以尽管setTimeout中状态发生了变化到fulfilled,但是then方法已经先一步执行了,所以无法输出“哈哈”
 
 
解决方法
- 我们需要在status === ‘PENDING’时,做一些判断
- 此时,我们执行then方法的时候,status为PENDING状态,所以我们可以将回调函数通过数组存储起来
 
- 当我们在setTimeout中调用resolve时,可以遍历数组,如果数组中有值,我们遍历调用数组中存储的回调函数callback
 
 
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
   | class MyPromise {   	...     constructor(func) { 				...         this.resolveCallBack = [];         this.rejectCallBack = []; 				...     }     resolve(result) {         if (this.status === MyPromise.PENDING) {             this.status = MyPromise.FULFILLED;             this.result = result;             this.resolveCallBack.forEach(callback => {                 callback(result);             })         }     }     reject(result) {         if (this.status === MyPromise.PENDING) {             this.status = MyPromise.REJECTED;             this.result = result;         }         this.rejectCallBack.forEach(callback => {             callback(result);         })     } }
  | 
 
此时,我们查看一下输出

现在,我们可以正常输出“哈哈”了。但是,我们的“哈哈”位置显然是不对的,正常情况下,他应该在5后面才输出的。
回顾实现代码,我们可以在resove和reject方法中使用setTimeout来保证输出机制
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
   | class MyPromise {   	...     constructor(func) { 				...         this.resolveCallBack = [];         this.rejectCallBack = []; 				...     }     resolve(result) {         setTimeout(() => {             if (this.status === MyPromise.PENDING) {                 this.status = MyPromise.FULFILLED;                 this.result = result;                 this.resolveCallBack.forEach(callback => {                     callback(result);                 })             }         });     }     reject(result) {         setTimeout(() => {             if (this.status === MyPromise.PENDING) {                 this.status = MyPromise.REJECTED;                 this.result = result;             }             this.rejectCallBack.forEach(callback => {                 callback(result);             })         });
      } }
  | 
 
现在,输出顺序如下

7. 链式
原生
我们知道, 在原生Promise中,Promise.then方法会返回一个then,可以进行链式调用
1 2 3 4 5 6 7 8 9 10
   | let promise1 = new Promise((resolve, reject) => {     resolve('哈哈') }) promise1.then(     result => { console.log(result)},     result => {console.log(result.message)} ).then(     result => { console.log('链式调用');},     result => { console.log(result.message) } )
  | 
 
输出
实现
目前效果

报错了,是因为我们的then方法并没有返回then方法,因此我们可以在then方法中return一个MyPromise,MyPromise有then方法,就可以实现链式调用了。
1 2 3 4 5 6 7 8 9 10 11
   | class MyPromise {   ....     then(onFulFILLED, onREJECTED) {         return new MyPromise((resolve, reject) => {             onFulFILLED = typeof onFulFILLED === 'function' ? onFulFILLED : () => { };             onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { }; 					...         })
      } }
  | 
 
这样就可以进行链式调用了,但是链式调用中的then并不能正常输出,还有很多细节~ 慢慢实现
总结
在这里,我从初始结构 -> 状态 -> 传参 -> then函数 -> Promise中异常处理 -> 异步 -> 链接来实现了简单版的Promise,虽然还有很多细节没有实现,但是收获很大。