手写实现一个Promise

promise是前端解决异步的一个重要的东西。其主要使用如下:

    const p1 = new Promise((resolve, reject) => {
      // 此处走then方法
      resolve(111)
      // 此处走catch方法
      // reject(222)
    })
    p1.then((res) => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })

1、先来实现一个基础版本

可以传入构造函数,有resolve,reject,可以调用then方法:

class MyPromise {
  constructor(executor) {
    //一共有三种状态,pending、fulfilled、reject
    this.status = 'pending';
    //成功的原因
    this.value = undefined;
    //失败的原因
    this.reason = undefined;

    let resolveFn = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.value = value;
      }
    }

    let rejectFn = (reason) => {
      if (this.status === 'pending') {
        this.status = 'reject';
        this.reason = reason;
      }
    }

    try {
      executor(resolveFn, rejectFn);
    } catch (e) {
      rejectFn(e)
    }
  }

  then (onFulFilled, onReject) {
    if (this.status === 'fulfilled') {
      onFulFilled(this.value)
    }
    if (this.status === 'reject') {
      onReject(this.reason)
    }
  }
}

const my1 = new MyPromise((resolve) => {
  console.log(1);
  resolve('resolve2')
})
my1.then(res => {
  console.log(res);
})

2、升级版本,遇到异步

在如果resolve没有立即执行,遇到了异步,应该如何解决,主要的思路就是:维护一个队列,加上一个数组去缓存执行函数:

我们分别维护了一个数组,当然我们在promise仍旧是pending状态的时候调用then方法,就会把这两个状态的回调函数缓存起来。等到我们调用resolve或者reject确认了promise的状态时,就会去调用对应的缓存队列执行回调。

    class MyPromise {
      constructor(executor) {
        executor(this.resolve.bind(this), this.reject.bind(this))
      }
      state = 'pending'
      // 成功的值
      value = null
      // 失败的值
      reason = null
      // 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
      onFulfilledCallbackList = []
      onRejectedCallbackList = []

      resolve(value) {
        if (this.state !== 'pending') return;
        this.state = 'fulfilled'
        this.value = value;
        // 状态变化的时候再去执行相应的函数,从队列里面出来
        this.onFulfilledCallbackList.forEach(callback => callback(value))
        this.onFulfilledCallbackList = []
      }
      reject(reason) {
        if (this.state !== 'pending') return;
        this.state = 'rejected'
        this.reason = reason
        this.onRejectedCallbackList.forEach(callback => callback(reason))
        this.onRejectedCallbackList = []
      }
      then(onFulFilled, onRejected) {
        return new MyPromise((res, rej) => {
          if (this.state === 'fulfilled') {
            res(onFulFilled(this.value))
          };
          if (this.state === 'rejected') {
            rej(onRejected(this.reason))
          };
          // 假如遇到了异步,那state依然是pengding状态,先放入队列里面
          if (this.state === 'pending') {
            this.onFulfilledCallbackList.push(onFulFilled)
            this.onRejectedCallbackList.push(onRejected)
          };

        })
      }
    }
    const myP1 = new MyPromise((resolve, reject) => {
      console.log('立即执行');
      resolve(111)
      // setTimeout(() => {
      //   resolve(111)
      // }, 3000)
    }).then(res => {
      console.log('成功了', res);
    }, err => {
      console.log('失败了', err);
    }).then(res => {
      console.log('链式调用then方法', res);
    })

3、实现then的链式调用

实现的思路就是在then方法中返回一个自己开发的promise就可以了关键代码如下:

class MyPromise {
  constructor(executor) {
    //一共有三种状态,pending、fulfilled、reject
    this.status = 'pending';
    //成功的原因
    this.value = undefined;
    //失败的原因
    this.reason = undefined;

    let resolveFn = (value) => {
      if (this.status === 'pending') {
        this.status = 'fulfilled';
        this.value = value;
      }
    }

    let rejectFn = (reason) => {
      if (this.status === 'pending') {
        this.status = 'reject';
        this.reason = reason;
      }
    }

    try {
      executor(resolveFn, rejectFn);
    } catch (e) {
      rejectFn(e)
    }
  }

  then (onFulFilled, onReject) {
    // 此次返回一个MyPromise就可以实现then的链式调用了,这里是关键代码
    return new MyPromise((resolve, reject) => {
      if (this.status === 'fulfilled') {
        // 将上一个promise的返回值传入到下一个构造函数的resolve方法中,如此就实现了then的链式调用
        resolve(onFulFilled(this.value))
      }
      if (this.status === 'reject') {
        reject(onReject(this.reason))
      }
    })
  }
}

const my1 = new MyPromise((resolve) => {
  console.log(1);
  resolve('resolve2')
})
my1.then(res => {
  console.log(res);
  return '25'
}).then(res => {
  console.log(res);
  return '35'
}).then(res => {
  console.log(res);
  return '45'
}).then(res => {
  console.log(res);
})
// 打印结果为:1,resolve2,25,35,45

4、实现Promise.resolve、Promise.reject和Promise.catch

这里主要就是讲解catch、resolve、reject方法是如何实现的; 

  class MyPromise {
    constructor(executor) {
      executor(this.resolve.bind(this), this.reject.bind(this))
    }
    state = 'pending'
    // 成功的值
    value = null
    // 失败的值
    reason = null
    // 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
    onFulfilledCallbackList = []
    onRejectedCallbackList = []

    resolve(value) {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled'
      this.value = value;
      // 状态变化的时候再去执行相应的函数,从队列里面出来
      this.onFulfilledCallbackList.forEach(callback => callback(value))
      this.onFulfilledCallbackList = []
    }
    reject(reason) {
      if (this.state !== 'pending') return;
      this.state = 'rejected'
      this.reason = reason
      this.onRejectedCallbackList.forEach(callback => callback(reason))
      this.onRejectedCallbackList = []
    }
    then(onFulFilled, onRejected) {
      return new MyPromise((res, rej) => {
        if (this.state === 'fulfilled') {
          res(onFulFilled(this.value))
        };
        if (this.state === 'rejected') {
          rej(onRejected(this.reason))
        };
        // 假如遇到了异步,那state依然是pengding状态,先放入队列里面
        if (this.state === 'pending') {
          this.onFulfilledCallbackList.push(onFulFilled)
          this.onRejectedCallbackList.push(onRejected)
        };

      })
    }
    catch(errCb) {
      return this.then(null, errCb);
    }
    static resolve(value) {
      return new MyPromise((resolve, reject) => {
        resolve(value);
      });
    }
    static reject(value) {
      return new MyPromise((resolve, reject) => {
        reject(value);
      });
    }
  }
  const myP1 = new MyPromise((resolve, reject) => {
    console.log('立即执行');
    reject(111)
    // setTimeout(() => {
    //   reject(111)
    // }, 3000)
  })
  myP1.then(res => {
    console.log('不走这里', res);
  }, (err) => {
    console.log('onReject捕获了失败', err);
  }).catch(res => {
    console.log('myP1** catch 方法', res);
  })


MyPromise.reject('试一下MyPromise**reject').catch(res => {
  console.log(res);
})
MyPromise.resolve('试一下MyPromise**resolve').then(res => {
  console.log(res);
})

5、Promise.其他方法

5.1、Promise.all

all方法会接受一个都是Promise的数组,然后内部回去处理这个数组。

首先,我们声明了两个变量,一个存储结果的数组,这个结果是指resolve成功后的onFulfilled回调的value,一个是计数器。

然后,我们去循环整个传入的promises,让每一个promise传递给Promise.resolve去执行,然后,我们用一个processResult去处理返回的data和当前的下标i,

然后我们还要处理一下reject,那么这里要注意哈,对于all方法来说,只要有一个出错了,那么整个all执行的结果就是rejected的,所以reject不用特殊处理,直接reject就好了,不需要添加进数组这个那个的。

那么继续,processResult每当我们执行一次的时候,会根据传入的下标的位置去存储结果,这样处理其实就是为了按照传入promise的先后顺序去存储结果,然后先++times再去和promises的length长度去做比较,换句话说就是计数嘛,如果相等,就直接resolve最终的result即可。

以上就是全部的思路了,来看一下细节的代码:

    static all(promises) {
      let result = [];
      let times = 0;
      return new Promise((resolve, reject) => {
        function processResult(data, index) {
          result[index] = data;
          if (++times === promises.length) {
             resolve(result);
          }
        }
      for (let i = 0; i < promises.length; i++) {
        const promise = promises[i];
        Promise.resolve(promise).then((data) => {
           processResult(data, i);
         }, reject);
        }
      });
    }

来看一下all的调用代码:

  const myP1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(111)
    }, 300)
  })

  const myP2 = new MyPromise((resolve, reject) => {
    resolve(222)
  })

  const myP3 = new MyPromise((resolve, reject) => {
    resolve(333)
  })

  const p = MyPromise.all([myP1, myP2, myP3]).then(res => {
    console.log('all', res);// 打印结果为:[111, 222, 333]
  })

 

5.2、Promise.race

先来看个例子:

const p = MyPromise.race([myP1, myP2, myP3])

race方法接收一个数组,数组中只要 myP1、myP2、myP3之中有一个实例率先改变状态,p的状态就跟着变。那个率先改变的promise实例的返回值,就传递给p的回调函数。

换句话说就是,只要有一个结果就行了,不管这个结果是啥。谁跑的快我就算谁是第一,这就是race的意思。所以需要循环一下全部执行一遍,谁有结果了就完事儿了。

关键代码如下:

    static race(promises) {
      return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
          let promise = promises[i];
          Promise.resolve(promise).then(resolve, reject);
        }
      });
    }

来看一下调用:

  const myP1 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(111)
    }, 300)
  })

  const myP2 = new MyPromise((resolve, reject) => {
    resolve(222)
  })

  const myP3 = new MyPromise((resolve, reject) => {
    resolve(333)
  })

  const p = MyPromise.race([myP1, myP2, myP3]).then(res => {
    console.log('race', res);// 打印结果为 222
  })

5.3、Promise.allSettled

这个方法的意思就是不管成功或者失败,会返回所有异步的结果。

其实跟all方法很类似,只要修改一下all方法就可以了,result存的内容也不太一样,多了个状态,会告诉你是失败的结果还是成功的结果。关键代码如下:

    static allSettled(promises) {
      let result = [];
      let times = 0;
      return new Promise((resolve, reject) => {
        function processResult(data, index, status) {
          // 这里调整成了对象的形式
          result[index] = { status, value: data };
          if (++times === promises.length) {
            resolve(result);
          }
         }
        for (let i = 0; i < promises.length; i++) {
         const promise = promises[i];
         // 不管成功与失败就都这样子来
         Promise.resolve(promise).then(
           (data) => {
             processResult(data, i, "fulfilled");
           },
           (err) => {
             processResult(err, i, "rejected");
           }
         );
        }
       });
    }

来看一下调用allSettled方法吧:

  const myP1= new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(111)
    }, 300)
  })

  const myP2 = new MyPromise((resolve, reject) => {
    reject(222)
  })

  const myP3 = new MyPromise((resolve, reject) => {
    resolve(333)
  })

  const p = MyPromise.allSettled([myP1, myP2, myP3]).then(res => {
    console.log('all', res);
    /*

    打印结果如下:
[
  {
    "status": "fulfilled",
    "value": 111
  },
  {
    "status": "rejected",
    "value": 222
  },
  {
    "status": "fulfilled",
    "value": 333
  }
]

*/ 
  })

5.4、Promise.finally

这个方法表示的意思是,不管Promise对象最后的状态如何,都会执行这个方法,就是我不管你Promise最后是fulfilled还是rejected,都会执行finally的回调。关键代码如下:

    finally(finallyCallback) {
      let p = this.constructor;
      return this.then(
        (data) => {
          return p.resolve(finallyCallback()).then(() => data);
        },
        (err) => {
          return p.resolve(finallyCallback()).then(() => {
              throw err;
          });
        }
     );
    }

调用的代码:

  MyPromise.resolve('test-finally').then(res => {
    console.log('then:', res);
  }, err => {
    console.log('catch:', err);
  }).finally(() => {
    console.log('finally');
  })
  
  /*
  * 最终打印结果为:
  * then: test-finally
  * finally
  * */

6、完整的代码

这个完整的代码包含:基础版本,升级版本,resolve、reject、then、catch、all、race、allSettled、finally,如下所示:

  class MyPromise {
    constructor(executor) {
      executor(this.resolveFn.bind(this), this.rejectFn.bind(this))
    }
    state = 'pending'
    // 成功的值
    value = null
    // 失败的值
    reason = null
    // 当走到then/catch方法的时候,如果状态没变化,就暂时先声明一个变量去缓存方法,等到状态变化的时候再去执行
    onFulfilledCallbackList = []
    onRejectedCallbackList = []

    resolveFn(value) {
      if (this.state !== 'pending') return;
      this.state = 'fulfilled'
      this.value = value;
      // 状态变化的时候再去执行相应的函数,从队列里面出来
      this.onFulfilledCallbackList.forEach(callback => callback(value))
      this.onFulfilledCallbackList = []
    }
    rejectFn(reason) {
      if (this.state !== 'pending') return;
      this.state = 'rejected'
      this.reason = reason
      this.onRejectedCallbackList.forEach(callback => callback(reason))
      this.onRejectedCallbackList = []
    }
    then(onFulFilled, onRejected) {
      return new MyPromise((res, rej) => {
        if (this.state === 'fulfilled') {
          res(onFulFilled(this.value))
        };
        if (this.state === 'rejected') {
          rej(onRejected(this.reason))
        };
        // 假如遇到了异步,那state依然是pengding状态,先放入队列里面
        if (this.state === 'pending') {
          this.onFulfilledCallbackList.push(onFulFilled)
          this.onRejectedCallbackList.push(onRejected)
        };

      })
    }
    catch(errCb) {
      return this.then(null, errCb);
    }
    static resolve(value) {
      return new MyPromise((resolve, reject) => {
        resolve(value);
      });
    }
    static reject(value) {
      return new MyPromise((resolve, reject) => {
        reject(value);
      });
    }

    static all(promises) {
      let result = [];
      let times = 0;
      return new Promise((resolve, reject) => {
        function processResult(data, index) {
          result[index] = data;
          if (++times === promises.length) {
             resolve(result);
          }
        }
      for (let i = 0; i < promises.length; i++) {
        const promise = promises[i];
        Promise.resolve(promise).then((data) => {
           processResult(data, i);
         }, reject);
        }
      });
    }

    static race(promises) {
      return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
          let promise = promises[i];
          Promise.resolve(promise).then(resolve, reject);
        }
      });
    }

    static allSettled(promises) {
      let result = [];
      let times = 0;
      return new Promise((resolve, reject) => {
        function processResult(data, index, status) {
          // 这里调整成了对象的形式
          result[index] = { status, value: data };
          if (++times === promises.length) {
            resolve(result);
          }
         }
        for (let i = 0; i < promises.length; i++) {
         const promise = promises[i];
         // 不管成功与失败就都这样子来
         Promise.resolve(promise).then(
           (data) => {
             processResult(data, i, "fulfilled");
           },
           (err) => {
             processResult(err, i, "rejected");
           }
         );
        }
       });
    }

    finally(finallyCallback) {
      let p = this.constructor;
      return this.then(
        (data) => {
          return p.resolve(finallyCallback()).then(() => data);
        },
        (err) => {
          return p.resolve(finallyCallback()).then(() => {
              throw err;
          });
        }
     );
    }

  }

最后:参考链接

参考链接

这个链接里面讲的很详细了,有空看一下,把他们都内化成自己的知识。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的手写Promise实现: ```javascript class MyPromise { constructor(executor) { this.state = 'pending'; this.value = null; this.reason = null; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; this.onFulfilledCallbacks.forEach((callback) => callback(this.value)); } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; this.onRejectedCallbacks.forEach((callback) => callback(this.reason)); } }; try { executor(resolve, reject); } catch (error) { reject(error); } } then(onFulfilled, onRejected) { onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (value) => value; onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason; }; const promise2 = new MyPromise((resolve, reject) => { if (this.state === 'fulfilled') { setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } else if (this.state === 'rejected') { setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } else { this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); } }); return promise2; } catch(onRejected) { return this.then(null, onRejected); } resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { reject(new TypeError('Chaining cycle detected')); } let called = false; if (x instanceof MyPromise) { x.then((value) => { this.resolvePromise(promise2, value, resolve, reject); }, (reason) => { if (!called) { called = true; reject(reason); } }); } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { try { const then = x.then; if (typeof then === 'function') { then.call(x, (value) => { if (!called) { called = true; this.resolvePromise(promise2, value, resolve, reject); } }, (reason) => { if (!called) { called = true; reject(reason); } }); } else { resolve(x); } } catch (error) { if (!called) { called = true; reject(error); } } } else { resolve(x); } } static resolve(value) { return new MyPromise((resolve) => { resolve(value); }); } static reject(reason) { return new MyPromise((resolve, reject) => { reject(reason); }); } static all(promises) { const results = []; return new MyPromise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { const promise = promises[i]; if (!(promise instanceof MyPromise)) { promise = MyPromise.resolve(promise); } promise.then((value) => { results[i] = value; if (results.length === promises.length) { resolve(results); } }, (reason) => { reject(reason); }); } }); } static race(promises) { return new MyPromise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { const promise = promises[i]; if (!(promise instanceof MyPromise)) { promise = MyPromise.resolve(promise); } promise.then((value) => { resolve(value); }, (reason) => { reject(reason); }); } }); } } ``` 这个实现包含了Promise的基本功能,包括resolve、reject、then、catch、resolvePromise等方法,并且还实现Promise.all和Promise.race方法。但是这个实现并不完整,还有很多细节需要考虑和完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值