Promise(1)

82 阅读2分钟

先熟悉一下基本用法

  • 前提,你要对js中的函数的用法,ES6新增的箭头函数和Promise的基本用法特别熟悉。
  • 而且promise的设计在于状态的改变以及回调函数的传参。
  • 先展示了一个最基本的用法
    function fn1() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log('定时器执行了');
          resolve('我会把这句话传递给then')
        }, 500)
      }
      )
    }
    fn1().then(res => {
      console.log(res);
    })
    //打印
    //定时器执行了
    //我会把这句话传递给then
  • 要清楚这几点,对后面写源码很重要
    1. Promise 接受1个参数,这个参数是一个函数(函数体)
    2. 函数体接受2个参数,可以叫他们回调函数, 而这个2个回调函数的函数体是在then中我们自己定义的,一般都喜欢写成箭头函数的形式(let resolve=>{ console.log(res);})
    3. 因此, Promise结构就变成了这样Promise(函数体(resolve,reject))
    4. 当我们new Promise之后,里面的函数体就会自动执行,函数体的调用写在Promise内部
    5. 执行之后会执行setTimeout和resolve,
    6. 对于resolve,声明放在函数体的参数里面,执行放在函数体的里面
  • 当你完全理解了上面的含义之后,基本上就能写成一个简单的源码了,让我们来实现一下吧

简单的源码

  • 完成简单的状态过程(最好自己去跟着调试走一遍)
      //最基本的promise,不支持异步和链式调用
      //一般我们把复用的变量定义在外面
      const PENDING = "PENDING";
      const RESOLVED = "RESOLVED";
      const REJECTED = "REJECTED";
      class Promise {
        constructor(executor) {
          //定义初始状态
          this.status = PENDING;
          //定义成功和失败的回调函数的参数
          this.value = undefined;
          this.reason = undefined;
          let resolve = (value) => {
            //确保状态为PENGDING的时候才能被改变
            if (this.status === PENDING) {
              //改变状态
              this.status = RESOLVED;
              //并且把resolve(value) 传给Promise.value = value
              this.value = value;
            }
          };
          let reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
            }
          };
          //如果失败了就直接执行reject
          try {
            executor(resolve,reject);
          } catch (e) {
            reject(e);
          }
        }
        //Promise的then方法
        then(onfulfilled, onrejected) {
          if (this.status === RESOLVED) {
            //执行成功回调并传出去参数
            onfulfilled(this.value);
          }
          if (this.status === REJECTED) {
            onrejected(this.reason);
          }
        }
      }
      function fn1() {
        return new Promise((resolve, reject) => {
          console.log("我只想了");
          resolve("我会把内容传递出去");
        });
      }
      fn1().then((res) => {
        console.log(res);
      });
  • 第二步加上异步回调的过程
      const PENDING = "PENDING";
      const RESOLVED = "RESOLVED";
      const REJECTED = "REJECTED";
      class Promise {
        constructor(executor) {
          this.status = PENDING;
          this.value = undefined;
          this.reason = undefined;
          //添加异步任务的执行队列
          this.resolveCb = [];
          this.rejectCb = [];
          let resolve = (value) => {
            if (this.status === PENDING) {
              this.status = RESOLVED;
              this.value = value;
              //如果状态改变了就执行对应的回调队列
              this.resolveCb.forEach(fn=>{
                fn()
              })
            }
          };
          let reject = (reason) => {
            if (this.status === PENDING) {
              this.status = REJECTED;
              this.reason = reason;
              this.rejectCb.forEach(fn=>{
                fn()
              })
            }
          };
          try {
            executor(resolve,reject);
          } catch (e) {
            reject(e);
          }
        }
        then(onfulfilled, onrejected) {
          if (this.status === RESOLVED) {
            onfulfilled(this.value);
          }
          if (this.status === REJECTED) {
            onrejected(this.reason);
          }
          //此时fn1(),执行了马上执行then()
          //但是因为异步关系resolve还没执行,
          //因此把后续回调放在resolve中回调执行
          if(this.status === PENDING){
            //注意这里的回调添加
            //为了把参数传过去,在函数体再添加函数的调用
            this.resolveCb.push(()=>{
              onfulfilled(this.value);
            })
            this.rejectCb.push(()=>{
              onrejected(this.reason);
            })
          }
        }
      }
      function fn1() {
        return new Promise((resolve, reject) => {
          setTimeout(()=>{
            console.log('我执行了');
            resolve('我会把这句话传递出去')
          },500)
        });
      }
      fn1().then((res) => {
        console.log(res);
      });